summary refs log tree commit diff
path: root/sound
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-05-23 08:52:38 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2011-05-23 08:52:38 -0700
commit710421cc7d295cc59eb2676fe2ba3bc3252c124e (patch)
tree4aa11cd7ee64b394871195cb585f16700553f540 /sound
parentd7ef64a9f9987b29e3d911369a9d40122d5be2dd (diff)
parentf686c74cc3e78349d16d46fc72807354574b1516 (diff)
downloadlinux-710421cc7d295cc59eb2676fe2ba3bc3252c124e.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: (346 commits)
  ASoC: core: Don't set "(null)" as a driver name
  ALSA: hda - Use LPIB for ATI/AMD chipsets as default
  Revert "ALSA: hda - Use position_fix=3 as default for AMD chipsets"
  ASoC: Tegra: Fix compile when debugfs not enabled
  ASoC: spdif-dit: Add missing MODULE_*
  SOUND: OSS: Remove Au1550 driver.
  ALSA: hda - add Intel Panther Point HDMI codec id
  ALSA: emu10k1 - Add dB range to Bass and Treble for SB Live!
  ALSA: hda - Remove PCM mixer elements from Virtual Master of realtek
  ALSA: hda - Fix input-src parse in patch_analog.c
  ASoC: davinci-mcasp: enable ping-pong SRAM buffers
  ASoC: add iPAQ hx4700 machine driver
  ASoC: Asahi Kasei AK4641 codec driver
  ALSA: hda - Enable Realtek ALC269 codec input layer beep
  ALSA: intel8x0m: enable AMD8111 modem
  ALSA: HDA: Add jack detection for HDMI
  ALSA: sound, core, pcm_lib: fix xrun_log
  ASoC: Max98095: Move existing NULL check before pointer dereference.
  ALSA: sound, core, pcm_lib: xrun_log: log also in_interrupt
  ALSA: usb-audio - Add support for USB X-Fi S51 Pro
  ...
Diffstat (limited to 'sound')
-rw-r--r--sound/core/control.c64
-rw-r--r--sound/core/init.c2
-rw-r--r--sound/core/pcm_lib.c14
-rw-r--r--sound/firewire/Kconfig11
-rw-r--r--sound/firewire/Makefile2
-rw-r--r--sound/firewire/isight.c755
-rw-r--r--sound/firewire/iso-resources.c5
-rw-r--r--sound/firewire/packets-buffer.c2
-rw-r--r--sound/i2c/other/Makefile2
-rw-r--r--sound/i2c/other/tea575x-tuner.c153
-rw-r--r--sound/oss/Kconfig4
-rw-r--r--sound/oss/Makefile1
-rw-r--r--sound/oss/ac97_codec.c1203
-rw-r--r--sound/oss/au1550_ac97.c2147
-rw-r--r--sound/pci/Kconfig27
-rw-r--r--sound/pci/Makefile1
-rw-r--r--sound/pci/asihpi/asihpi.c328
-rw-r--r--sound/pci/asihpi/hpi6000.c39
-rw-r--r--sound/pci/asihpi/hpi6205.c95
-rw-r--r--sound/pci/asihpi/hpi_internal.h19
-rw-r--r--sound/pci/asihpi/hpicmn.c10
-rw-r--r--sound/pci/asihpi/hpicmn.h2
-rw-r--r--sound/pci/asihpi/hpifunc.c27
-rw-r--r--sound/pci/asihpi/hpimsgx.c31
-rw-r--r--sound/pci/asihpi/hpioctl.c63
-rw-r--r--sound/pci/au88x0/au8810.h2
-rw-r--r--sound/pci/au88x0/au8820.h2
-rw-r--r--sound/pci/au88x0/au8830.h2
-rw-r--r--sound/pci/au88x0/au88x0_pcm.c13
-rw-r--r--sound/pci/emu10k1/emufx.c5
-rw-r--r--sound/pci/emu10k1/emumixer.c10
-rw-r--r--sound/pci/es1968.c78
-rw-r--r--sound/pci/fm801.c371
-rw-r--r--sound/pci/hda/hda_codec.c97
-rw-r--r--sound/pci/hda/hda_codec.h4
-rw-r--r--sound/pci/hda/hda_intel.c38
-rw-r--r--sound/pci/hda/hda_local.h16
-rw-r--r--sound/pci/hda/patch_analog.c345
-rw-r--r--sound/pci/hda/patch_ca0110.c16
-rw-r--r--sound/pci/hda/patch_cirrus.c52
-rw-r--r--sound/pci/hda/patch_cmedia.c40
-rw-r--r--sound/pci/hda/patch_conexant.c1085
-rw-r--r--sound/pci/hda/patch_hdmi.c39
-rw-r--r--sound/pci/hda/patch_realtek.c3681
-rw-r--r--sound/pci/hda/patch_si3054.c11
-rw-r--r--sound/pci/hda/patch_sigmatel.c431
-rw-r--r--sound/pci/hda/patch_via.c1526
-rw-r--r--sound/pci/intel8x0m.c4
-rw-r--r--sound/pci/lola/Makefile4
-rw-r--r--sound/pci/lola/lola.c791
-rw-r--r--sound/pci/lola/lola.h527
-rw-r--r--sound/pci/lola/lola_clock.c323
-rw-r--r--sound/pci/lola/lola_mixer.c839
-rw-r--r--sound/pci/lola/lola_pcm.c706
-rw-r--r--sound/pci/lola/lola_proc.c222
-rw-r--r--sound/ppc/tumbler.c2
-rw-r--r--sound/soc/atmel/sam9g20_wm8731.c2
-rw-r--r--sound/soc/au1x/db1200.c2
-rw-r--r--sound/soc/blackfin/bf5xx-ac97-pcm.c13
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.c166
-rw-r--r--sound/soc/blackfin/bf5xx-ad1836.c42
-rw-r--r--sound/soc/blackfin/bf5xx-ad193x.c56
-rw-r--r--sound/soc/blackfin/bf5xx-ad1980.c45
-rw-r--r--sound/soc/blackfin/bf5xx-ad73311.c42
-rw-r--r--sound/soc/blackfin/bf5xx-i2s-pcm.c23
-rw-r--r--sound/soc/blackfin/bf5xx-i2s.c172
-rw-r--r--sound/soc/blackfin/bf5xx-sport.c159
-rw-r--r--sound/soc/blackfin/bf5xx-sport.h16
-rw-r--r--sound/soc/blackfin/bf5xx-ssm2602.c42
-rw-r--r--sound/soc/blackfin/bf5xx-tdm-pcm.c23
-rw-r--r--sound/soc/blackfin/bf5xx-tdm.c110
-rw-r--r--sound/soc/codecs/88pm860x-codec.c2
-rw-r--r--sound/soc/codecs/Kconfig20
-rw-r--r--sound/soc/codecs/Makefile10
-rw-r--r--sound/soc/codecs/ad193x.c23
-rw-r--r--sound/soc/codecs/ad1980.c2
-rw-r--r--sound/soc/codecs/ad73311.c2
-rw-r--r--sound/soc/codecs/ak4535.c19
-rw-r--r--sound/soc/codecs/ak4641.c664
-rw-r--r--sound/soc/codecs/ak4641.h47
-rw-r--r--sound/soc/codecs/ak4671.c18
-rw-r--r--sound/soc/codecs/cx20442.c18
-rw-r--r--sound/soc/codecs/dmic.c26
-rw-r--r--sound/soc/codecs/jz4740.c18
-rw-r--r--sound/soc/codecs/max98088.c87
-rw-r--r--sound/soc/codecs/max98088.h13
-rw-r--r--sound/soc/codecs/max98095.c2396
-rw-r--r--sound/soc/codecs/max98095.h299
-rw-r--r--sound/soc/codecs/sn95031.c17
-rw-r--r--sound/soc/codecs/spdif_transciever.c8
-rw-r--r--sound/soc/codecs/ssm2602.c464
-rw-r--r--sound/soc/codecs/ssm2602.h6
-rw-r--r--sound/soc/codecs/tlv320aic23.c19
-rw-r--r--sound/soc/codecs/tlv320aic3x.c3
-rw-r--r--sound/soc/codecs/tlv320dac33.c17
-rw-r--r--sound/soc/codecs/tlv320dac33.h2
-rw-r--r--sound/soc/codecs/tpa6130a2.c4
-rw-r--r--sound/soc/codecs/tpa6130a2.h2
-rw-r--r--sound/soc/codecs/twl6040.c6
-rw-r--r--sound/soc/codecs/wm1250-ev1.c108
-rw-r--r--sound/soc/codecs/wm8711.c18
-rw-r--r--sound/soc/codecs/wm8728.c18
-rw-r--r--sound/soc/codecs/wm8731.c22
-rw-r--r--sound/soc/codecs/wm8903.c44
-rw-r--r--sound/soc/codecs/wm8915.c2931
-rw-r--r--sound/soc/codecs/wm8915.h3717
-rw-r--r--sound/soc/codecs/wm8958-dsp2.c1051
-rw-r--r--sound/soc/codecs/wm8962.c63
-rw-r--r--sound/soc/codecs/wm8993.c3
-rw-r--r--sound/soc/codecs/wm8994.c395
-rw-r--r--sound/soc/codecs/wm8994.h97
-rw-r--r--sound/soc/codecs/wm8995.c4
-rw-r--r--sound/soc/codecs/wm9705.c18
-rw-r--r--sound/soc/codecs/wm9712.c18
-rw-r--r--sound/soc/codecs/wm9713.c19
-rw-r--r--sound/soc/codecs/wm_hubs.c24
-rw-r--r--sound/soc/davinci/davinci-mcasp.c2
-rw-r--r--sound/soc/imx/imx-ssi.c6
-rw-r--r--sound/soc/jz4740/qi_lb60.c46
-rw-r--r--sound/soc/mid-x86/sst_platform.c4
-rw-r--r--sound/soc/omap/omap-mcbsp.c6
-rw-r--r--sound/soc/omap/omap-mcbsp.h2
-rw-r--r--sound/soc/omap/omap-pcm.c7
-rw-r--r--sound/soc/omap/omap-pcm.h2
-rw-r--r--sound/soc/omap/rx51.c2
-rw-r--r--sound/soc/pxa/Kconfig9
-rw-r--r--sound/soc/pxa/Makefile2
-rw-r--r--sound/soc/pxa/corgi.c2
-rw-r--r--sound/soc/pxa/hx4700.c255
-rw-r--r--sound/soc/pxa/poodle.c2
-rw-r--r--sound/soc/pxa/spitz.c41
-rw-r--r--sound/soc/samsung/Kconfig15
-rw-r--r--sound/soc/samsung/Makefile4
-rw-r--r--sound/soc/samsung/goni_wm8994.c1
-rw-r--r--sound/soc/samsung/neo1973_wm8753.c1
-rw-r--r--sound/soc/samsung/smdk_wm8580pcm.c206
-rw-r--r--sound/soc/samsung/speyside.c332
-rw-r--r--sound/soc/sh/fsi.c188
-rw-r--r--sound/soc/soc-cache.c612
-rw-r--r--sound/soc/soc-core.c191
-rw-r--r--sound/soc/soc-dapm.c611
-rw-r--r--sound/soc/soc-jack.c2
-rw-r--r--sound/soc/soc-utils.c53
-rw-r--r--sound/soc/tegra/Kconfig38
-rw-r--r--sound/soc/tegra/Makefile14
-rw-r--r--sound/soc/tegra/harmony.c394
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.c9
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.h2
-rw-r--r--sound/soc/tegra/tegra_i2s.c2
-rw-r--r--sound/soc/tegra/tegra_wm8903.c475
-rw-r--r--sound/soc/tegra/trimslice.c228
-rw-r--r--sound/usb/6fire/control.c105
-rw-r--r--sound/usb/6fire/control.h17
-rw-r--r--sound/usb/6fire/firmware.c73
-rw-r--r--sound/usb/6fire/pcm.c97
-rw-r--r--sound/usb/Kconfig10
-rw-r--r--sound/usb/clock.c11
-rw-r--r--sound/usb/debug.h2
-rw-r--r--sound/usb/format.c1
-rw-r--r--sound/usb/mixer.c10
-rw-r--r--sound/usb/mixer_quirks.c12
-rw-r--r--sound/usb/quirks-table.h47
-rw-r--r--sound/usb/quirks.c1
163 files changed, 24130 insertions, 9986 deletions
diff --git a/sound/core/control.c b/sound/core/control.c
index a08ad57c49b6..5d98194bcad5 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -366,6 +366,70 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
 EXPORT_SYMBOL(snd_ctl_add);
 
 /**
+ * snd_ctl_replace - replace the control instance of the card
+ * @card: the card instance
+ * @kcontrol: the control instance to replace
+ * @add_on_replace: add the control if not already added
+ *
+ * Replaces the given control.  If the given control does not exist
+ * and the add_on_replace flag is set, the control is added.  If the
+ * control exists, it is destroyed first.
+ *
+ * Returns zero if successful, or a negative error code on failure.
+ *
+ * It frees automatically the control which cannot be added or replaced.
+ */
+int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
+		    bool add_on_replace)
+{
+	struct snd_ctl_elem_id id;
+	unsigned int idx;
+	struct snd_kcontrol *old;
+	int ret;
+
+	if (!kcontrol)
+		return -EINVAL;
+	if (snd_BUG_ON(!card || !kcontrol->info)) {
+		ret = -EINVAL;
+		goto error;
+	}
+	id = kcontrol->id;
+	down_write(&card->controls_rwsem);
+	old = snd_ctl_find_id(card, &id);
+	if (!old) {
+		if (add_on_replace)
+			goto add;
+		up_write(&card->controls_rwsem);
+		ret = -EINVAL;
+		goto error;
+	}
+	ret = snd_ctl_remove(card, old);
+	if (ret < 0) {
+		up_write(&card->controls_rwsem);
+		goto error;
+	}
+add:
+	if (snd_ctl_find_hole(card, kcontrol->count) < 0) {
+		up_write(&card->controls_rwsem);
+		ret = -ENOMEM;
+		goto error;
+	}
+	list_add_tail(&kcontrol->list, &card->controls);
+	card->controls_count += kcontrol->count;
+	kcontrol->id.numid = card->last_numid + 1;
+	card->last_numid += kcontrol->count;
+	up_write(&card->controls_rwsem);
+	for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
+		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
+	return 0;
+
+error:
+	snd_ctl_free_one(kcontrol);
+	return ret;
+}
+EXPORT_SYMBOL(snd_ctl_replace);
+
+/**
  * snd_ctl_remove - remove the control from the card and release it
  * @card: the card instance
  * @kcontrol: the control instance to remove
diff --git a/sound/core/init.c b/sound/core/init.c
index a0080aa45ae9..30ecad41403c 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -514,7 +514,7 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *nid)
 	id = card->id;
 	
 	if (*id == '\0')
-		strcpy(id, "default");
+		strcpy(id, "Default");
 
 	while (1) {
 	      	if (loops-- == 0) {
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 64449cb8f873..abfeff1611ce 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -189,6 +189,7 @@ static void xrun(struct snd_pcm_substream *substream)
 #define XRUN_LOG_CNT	10
 
 struct hwptr_log_entry {
+	unsigned int in_interrupt;
 	unsigned long jiffies;
 	snd_pcm_uframes_t pos;
 	snd_pcm_uframes_t period_size;
@@ -204,7 +205,7 @@ struct snd_pcm_hwptr_log {
 };
 
 static void xrun_log(struct snd_pcm_substream *substream,
-		     snd_pcm_uframes_t pos)
+		     snd_pcm_uframes_t pos, int in_interrupt)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_pcm_hwptr_log *log = runtime->hwptr_log;
@@ -220,6 +221,7 @@ static void xrun_log(struct snd_pcm_substream *substream,
 			return;
 	}
 	entry = &log->entries[log->idx];
+	entry->in_interrupt = in_interrupt;
 	entry->jiffies = jiffies;
 	entry->pos = pos;
 	entry->period_size = runtime->period_size;
@@ -246,9 +248,11 @@ static void xrun_log_show(struct snd_pcm_substream *substream)
 		entry = &log->entries[idx];
 		if (entry->period_size == 0)
 			break;
-		snd_printd("hwptr log: %s: j=%lu, pos=%ld/%ld/%ld, "
+		snd_printd("hwptr log: %s: %sj=%lu, pos=%ld/%ld/%ld, "
 			   "hwptr=%ld/%ld\n",
-			   name, entry->jiffies, (unsigned long)entry->pos,
+			   name, entry->in_interrupt ? "[Q] " : "",
+			   entry->jiffies,
+			   (unsigned long)entry->pos,
 			   (unsigned long)entry->period_size,
 			   (unsigned long)entry->buffer_size,
 			   (unsigned long)entry->old_hw_ptr,
@@ -262,7 +266,7 @@ static void xrun_log_show(struct snd_pcm_substream *substream)
 #else /* ! CONFIG_SND_PCM_XRUN_DEBUG */
 
 #define hw_ptr_error(substream, fmt, args...) do { } while (0)
-#define xrun_log(substream, pos)	do { } while (0)
+#define xrun_log(substream, pos, in_interrupt)	do { } while (0)
 #define xrun_log_show(substream)	do { } while (0)
 
 #endif
@@ -326,7 +330,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
 	}
 	pos -= pos % runtime->min_align;
 	if (xrun_debug(substream, XRUN_DEBUG_LOG))
-		xrun_log(substream, pos);
+		xrun_log(substream, pos, in_interrupt);
 	hw_base = runtime->hw_ptr_base;
 	new_hw_ptr = hw_base + pos;
 	if (in_interrupt) {
diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig
index e486f48660fb..26071489970b 100644
--- a/sound/firewire/Kconfig
+++ b/sound/firewire/Kconfig
@@ -22,4 +22,15 @@ config SND_FIREWIRE_SPEAKERS
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-firewire-speakers.
 
+config SND_ISIGHT
+	tristate "Apple iSight microphone"
+	select SND_PCM
+	select SND_FIREWIRE_LIB
+	help
+	  Say Y here to include support for the front and rear microphones
+	  of the Apple iSight web camera.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-isight.
+
 endif # SND_FIREWIRE
diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile
index e5b1634d9ad4..d71ed8935f76 100644
--- a/sound/firewire/Makefile
+++ b/sound/firewire/Makefile
@@ -1,6 +1,8 @@
 snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \
 			 fcp.o cmp.o amdtp.o
 snd-firewire-speakers-objs := speakers.o
+snd-isight-objs := isight.o
 
 obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o
 obj-$(CONFIG_SND_FIREWIRE_SPEAKERS) += snd-firewire-speakers.o
+obj-$(CONFIG_SND_ISIGHT) += snd-isight.o
diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c
new file mode 100644
index 000000000000..86ee16ca365e
--- /dev/null
+++ b/sound/firewire/isight.c
@@ -0,0 +1,755 @@
+/*
+ * Apple iSight audio driver
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <asm/byteorder.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+#include "lib.h"
+#include "iso-resources.h"
+#include "packets-buffer.h"
+
+#define OUI_APPLE		0x000a27
+#define MODEL_APPLE_ISIGHT	0x000008
+#define SW_ISIGHT_AUDIO		0x000010
+
+#define REG_AUDIO_ENABLE	0x000
+#define  AUDIO_ENABLE		0x80000000
+#define REG_DEF_AUDIO_GAIN	0x204
+#define REG_GAIN_RAW_START	0x210
+#define REG_GAIN_RAW_END	0x214
+#define REG_GAIN_DB_START	0x218
+#define REG_GAIN_DB_END		0x21c
+#define REG_SAMPLE_RATE_INQUIRY	0x280
+#define REG_ISO_TX_CONFIG	0x300
+#define  SPEED_SHIFT		16
+#define REG_SAMPLE_RATE		0x400
+#define  RATE_48000		0x80000000
+#define REG_GAIN		0x500
+#define REG_MUTE		0x504
+
+#define MAX_FRAMES_PER_PACKET	475
+
+#define QUEUE_LENGTH		20
+
+struct isight {
+	struct snd_card *card;
+	struct fw_unit *unit;
+	struct fw_device *device;
+	u64 audio_base;
+	struct fw_address_handler iris_handler;
+	struct snd_pcm_substream *pcm;
+	struct mutex mutex;
+	struct iso_packets_buffer buffer;
+	struct fw_iso_resources resources;
+	struct fw_iso_context *context;
+	bool pcm_active;
+	bool pcm_running;
+	bool first_packet;
+	int packet_index;
+	u32 total_samples;
+	unsigned int buffer_pointer;
+	unsigned int period_counter;
+	s32 gain_min, gain_max;
+	unsigned int gain_tlv[4];
+};
+
+struct audio_payload {
+	__be32 sample_count;
+	__be32 signature;
+	__be32 sample_total;
+	__be32 reserved;
+	__be16 samples[2 * MAX_FRAMES_PER_PACKET];
+};
+
+MODULE_DESCRIPTION("iSight audio driver");
+MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
+MODULE_LICENSE("GPL v2");
+
+static struct fw_iso_packet audio_packet = {
+	.payload_length = sizeof(struct audio_payload),
+	.interrupt = 1,
+	.header_length = 4,
+};
+
+static void isight_update_pointers(struct isight *isight, unsigned int count)
+{
+	struct snd_pcm_runtime *runtime = isight->pcm->runtime;
+	unsigned int ptr;
+
+	smp_wmb(); /* update buffer data before buffer pointer */
+
+	ptr = isight->buffer_pointer;
+	ptr += count;
+	if (ptr >= runtime->buffer_size)
+		ptr -= runtime->buffer_size;
+	ACCESS_ONCE(isight->buffer_pointer) = ptr;
+
+	isight->period_counter += count;
+	if (isight->period_counter >= runtime->period_size) {
+		isight->period_counter -= runtime->period_size;
+		snd_pcm_period_elapsed(isight->pcm);
+	}
+}
+
+static void isight_samples(struct isight *isight,
+			   const __be16 *samples, unsigned int count)
+{
+	struct snd_pcm_runtime *runtime;
+	unsigned int count1;
+
+	if (!ACCESS_ONCE(isight->pcm_running))
+		return;
+
+	runtime = isight->pcm->runtime;
+	if (isight->buffer_pointer + count <= runtime->buffer_size) {
+		memcpy(runtime->dma_area + isight->buffer_pointer * 4,
+		       samples, count * 4);
+	} else {
+		count1 = runtime->buffer_size - isight->buffer_pointer;
+		memcpy(runtime->dma_area + isight->buffer_pointer * 4,
+		       samples, count1 * 4);
+		samples += count1 * 2;
+		memcpy(runtime->dma_area, samples, (count - count1) * 4);
+	}
+
+	isight_update_pointers(isight, count);
+}
+
+static void isight_pcm_abort(struct isight *isight)
+{
+	unsigned long flags;
+
+	if (ACCESS_ONCE(isight->pcm_active)) {
+		snd_pcm_stream_lock_irqsave(isight->pcm, flags);
+		if (snd_pcm_running(isight->pcm))
+			snd_pcm_stop(isight->pcm, SNDRV_PCM_STATE_XRUN);
+		snd_pcm_stream_unlock_irqrestore(isight->pcm, flags);
+	}
+}
+
+static void isight_dropped_samples(struct isight *isight, unsigned int total)
+{
+	struct snd_pcm_runtime *runtime;
+	u32 dropped;
+	unsigned int count1;
+
+	if (!ACCESS_ONCE(isight->pcm_running))
+		return;
+
+	runtime = isight->pcm->runtime;
+	dropped = total - isight->total_samples;
+	if (dropped < runtime->buffer_size) {
+		if (isight->buffer_pointer + dropped <= runtime->buffer_size) {
+			memset(runtime->dma_area + isight->buffer_pointer * 4,
+			       0, dropped * 4);
+		} else {
+			count1 = runtime->buffer_size - isight->buffer_pointer;
+			memset(runtime->dma_area + isight->buffer_pointer * 4,
+			       0, count1 * 4);
+			memset(runtime->dma_area, 0, (dropped - count1) * 4);
+		}
+		isight_update_pointers(isight, dropped);
+	} else {
+		isight_pcm_abort(isight);
+	}
+}
+
+static void isight_packet(struct fw_iso_context *context, u32 cycle,
+			  size_t header_length, void *header, void *data)
+{
+	struct isight *isight = data;
+	const struct audio_payload *payload;
+	unsigned int index, length, count, total;
+	int err;
+
+	if (isight->packet_index < 0)
+		return;
+	index = isight->packet_index;
+	payload = isight->buffer.packets[index].buffer;
+	length = be32_to_cpup(header) >> 16;
+
+	if (likely(length >= 16 &&
+		   payload->signature == cpu_to_be32(0x73676874/*"sght"*/))) {
+		count = be32_to_cpu(payload->sample_count);
+		if (likely(count <= (length - 16) / 4)) {
+			total = be32_to_cpu(payload->sample_total);
+			if (unlikely(total != isight->total_samples)) {
+				if (!isight->first_packet)
+					isight_dropped_samples(isight, total);
+				isight->first_packet = false;
+				isight->total_samples = total;
+			}
+
+			isight_samples(isight, payload->samples, count);
+			isight->total_samples += count;
+		}
+	}
+
+	err = fw_iso_context_queue(isight->context, &audio_packet,
+				   &isight->buffer.iso_buffer,
+				   isight->buffer.packets[index].offset);
+	if (err < 0) {
+		dev_err(&isight->unit->device, "queueing error: %d\n", err);
+		isight_pcm_abort(isight);
+		isight->packet_index = -1;
+		return;
+	}
+
+	if (++index >= QUEUE_LENGTH)
+		index = 0;
+	isight->packet_index = index;
+}
+
+static int isight_connect(struct isight *isight)
+{
+	int ch, err, rcode, errors = 0;
+	__be32 value;
+
+retry_after_bus_reset:
+	ch = fw_iso_resources_allocate(&isight->resources,
+				       sizeof(struct audio_payload),
+				       isight->device->max_speed);
+	if (ch < 0) {
+		err = ch;
+		goto error;
+	}
+
+	value = cpu_to_be32(ch | (isight->device->max_speed << SPEED_SHIFT));
+	for (;;) {
+		rcode = fw_run_transaction(
+				isight->device->card,
+				TCODE_WRITE_QUADLET_REQUEST,
+				isight->device->node_id,
+				isight->resources.generation,
+				isight->device->max_speed,
+				isight->audio_base + REG_ISO_TX_CONFIG,
+				&value, 4);
+		if (rcode == RCODE_COMPLETE) {
+			return 0;
+		} else if (rcode == RCODE_GENERATION) {
+			fw_iso_resources_free(&isight->resources);
+			goto retry_after_bus_reset;
+		} else if (rcode_is_permanent_error(rcode) || ++errors >= 3) {
+			err = -EIO;
+			goto err_resources;
+		}
+		msleep(5);
+	}
+
+err_resources:
+	fw_iso_resources_free(&isight->resources);
+error:
+	return err;
+}
+
+static int isight_open(struct snd_pcm_substream *substream)
+{
+	static const struct snd_pcm_hardware hardware = {
+		.info = SNDRV_PCM_INFO_MMAP |
+			SNDRV_PCM_INFO_MMAP_VALID |
+			SNDRV_PCM_INFO_BATCH |
+			SNDRV_PCM_INFO_INTERLEAVED |
+			SNDRV_PCM_INFO_BLOCK_TRANSFER,
+		.formats = SNDRV_PCM_FMTBIT_S16_BE,
+		.rates = SNDRV_PCM_RATE_48000,
+		.rate_min = 48000,
+		.rate_max = 48000,
+		.channels_min = 2,
+		.channels_max = 2,
+		.buffer_bytes_max = 4 * 1024 * 1024,
+		.period_bytes_min = MAX_FRAMES_PER_PACKET * 4,
+		.period_bytes_max = 1024 * 1024,
+		.periods_min = 2,
+		.periods_max = UINT_MAX,
+	};
+	struct isight *isight = substream->private_data;
+
+	substream->runtime->hw = hardware;
+
+	return iso_packets_buffer_init(&isight->buffer, isight->unit,
+				       QUEUE_LENGTH,
+				       sizeof(struct audio_payload),
+				       DMA_FROM_DEVICE);
+}
+
+static int isight_close(struct snd_pcm_substream *substream)
+{
+	struct isight *isight = substream->private_data;
+
+	iso_packets_buffer_destroy(&isight->buffer, isight->unit);
+
+	return 0;
+}
+
+static int isight_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *hw_params)
+{
+	struct isight *isight = substream->private_data;
+	int err;
+
+	err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
+					       params_buffer_bytes(hw_params));
+	if (err < 0)
+		return err;
+
+	ACCESS_ONCE(isight->pcm_active) = true;
+
+	return 0;
+}
+
+static int reg_read(struct isight *isight, int offset, __be32 *value)
+{
+	return snd_fw_transaction(isight->unit, TCODE_READ_QUADLET_REQUEST,
+				  isight->audio_base + offset, value, 4);
+}
+
+static int reg_write(struct isight *isight, int offset, __be32 value)
+{
+	return snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
+				  isight->audio_base + offset, &value, 4);
+}
+
+static void isight_stop_streaming(struct isight *isight)
+{
+	if (!isight->context)
+		return;
+
+	fw_iso_context_stop(isight->context);
+	fw_iso_context_destroy(isight->context);
+	isight->context = NULL;
+	fw_iso_resources_free(&isight->resources);
+	reg_write(isight, REG_AUDIO_ENABLE, 0);
+}
+
+static int isight_hw_free(struct snd_pcm_substream *substream)
+{
+	struct isight *isight = substream->private_data;
+
+	ACCESS_ONCE(isight->pcm_active) = false;
+
+	mutex_lock(&isight->mutex);
+	isight_stop_streaming(isight);
+	mutex_unlock(&isight->mutex);
+
+	return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int isight_start_streaming(struct isight *isight)
+{
+	unsigned int i;
+	int err;
+
+	if (isight->context) {
+		if (isight->packet_index < 0)
+			isight_stop_streaming(isight);
+		else
+			return 0;
+	}
+
+	err = reg_write(isight, REG_SAMPLE_RATE, cpu_to_be32(RATE_48000));
+	if (err < 0)
+		goto error;
+
+	err = isight_connect(isight);
+	if (err < 0)
+		goto error;
+
+	err = reg_write(isight, REG_AUDIO_ENABLE, cpu_to_be32(AUDIO_ENABLE));
+	if (err < 0)
+		goto err_resources;
+
+	isight->context = fw_iso_context_create(isight->device->card,
+						FW_ISO_CONTEXT_RECEIVE,
+						isight->resources.channel,
+						isight->device->max_speed,
+						4, isight_packet, isight);
+	if (IS_ERR(isight->context)) {
+		err = PTR_ERR(isight->context);
+		isight->context = NULL;
+		goto err_resources;
+	}
+
+	for (i = 0; i < QUEUE_LENGTH; ++i) {
+		err = fw_iso_context_queue(isight->context, &audio_packet,
+					   &isight->buffer.iso_buffer,
+					   isight->buffer.packets[i].offset);
+		if (err < 0)
+			goto err_context;
+	}
+
+	isight->first_packet = true;
+	isight->packet_index = 0;
+
+	err = fw_iso_context_start(isight->context, -1, 0,
+				   FW_ISO_CONTEXT_MATCH_ALL_TAGS/*?*/);
+	if (err < 0)
+		goto err_context;
+
+	return 0;
+
+err_context:
+	fw_iso_context_destroy(isight->context);
+	isight->context = NULL;
+err_resources:
+	fw_iso_resources_free(&isight->resources);
+	reg_write(isight, REG_AUDIO_ENABLE, 0);
+error:
+	return err;
+}
+
+static int isight_prepare(struct snd_pcm_substream *substream)
+{
+	struct isight *isight = substream->private_data;
+	int err;
+
+	isight->buffer_pointer = 0;
+	isight->period_counter = 0;
+
+	mutex_lock(&isight->mutex);
+	err = isight_start_streaming(isight);
+	mutex_unlock(&isight->mutex);
+
+	return err;
+}
+
+static int isight_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct isight *isight = substream->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		ACCESS_ONCE(isight->pcm_running) = true;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		ACCESS_ONCE(isight->pcm_running) = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static snd_pcm_uframes_t isight_pointer(struct snd_pcm_substream *substream)
+{
+	struct isight *isight = substream->private_data;
+
+	return ACCESS_ONCE(isight->buffer_pointer);
+}
+
+static int isight_create_pcm(struct isight *isight)
+{
+	static struct snd_pcm_ops ops = {
+		.open      = isight_open,
+		.close     = isight_close,
+		.ioctl     = snd_pcm_lib_ioctl,
+		.hw_params = isight_hw_params,
+		.hw_free   = isight_hw_free,
+		.prepare   = isight_prepare,
+		.trigger   = isight_trigger,
+		.pointer   = isight_pointer,
+		.page      = snd_pcm_lib_get_vmalloc_page,
+		.mmap      = snd_pcm_lib_mmap_vmalloc,
+	};
+	struct snd_pcm *pcm;
+	int err;
+
+	err = snd_pcm_new(isight->card, "iSight", 0, 0, 1, &pcm);
+	if (err < 0)
+		return err;
+	pcm->private_data = isight;
+	strcpy(pcm->name, "iSight");
+	isight->pcm = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+	isight->pcm->ops = &ops;
+
+	return 0;
+}
+
+static int isight_gain_info(struct snd_kcontrol *ctl,
+			    struct snd_ctl_elem_info *info)
+{
+	struct isight *isight = ctl->private_data;
+
+	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	info->count = 1;
+	info->value.integer.min = isight->gain_min;
+	info->value.integer.max = isight->gain_max;
+
+	return 0;
+}
+
+static int isight_gain_get(struct snd_kcontrol *ctl,
+			   struct snd_ctl_elem_value *value)
+{
+	struct isight *isight = ctl->private_data;
+	__be32 gain;
+	int err;
+
+	err = reg_read(isight, REG_GAIN, &gain);
+	if (err < 0)
+		return err;
+
+	value->value.integer.value[0] = (s32)be32_to_cpu(gain);
+
+	return 0;
+}
+
+static int isight_gain_put(struct snd_kcontrol *ctl,
+			   struct snd_ctl_elem_value *value)
+{
+	struct isight *isight = ctl->private_data;
+
+	if (value->value.integer.value[0] < isight->gain_min ||
+	    value->value.integer.value[0] > isight->gain_max)
+		return -EINVAL;
+
+	return reg_write(isight, REG_GAIN,
+			 cpu_to_be32(value->value.integer.value[0]));
+}
+
+static int isight_mute_get(struct snd_kcontrol *ctl,
+			   struct snd_ctl_elem_value *value)
+{
+	struct isight *isight = ctl->private_data;
+	__be32 mute;
+	int err;
+
+	err = reg_read(isight, REG_MUTE, &mute);
+	if (err < 0)
+		return err;
+
+	value->value.integer.value[0] = !mute;
+
+	return 0;
+}
+
+static int isight_mute_put(struct snd_kcontrol *ctl,
+			   struct snd_ctl_elem_value *value)
+{
+	struct isight *isight = ctl->private_data;
+
+	return reg_write(isight, REG_MUTE,
+			 (__force __be32)!value->value.integer.value[0]);
+}
+
+static int isight_create_mixer(struct isight *isight)
+{
+	static const struct snd_kcontrol_new gain_control = {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Mic Capture Volume",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+		.info = isight_gain_info,
+		.get = isight_gain_get,
+		.put = isight_gain_put,
+	};
+	static const struct snd_kcontrol_new mute_control = {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Mic Capture Switch",
+		.info = snd_ctl_boolean_mono_info,
+		.get = isight_mute_get,
+		.put = isight_mute_put,
+	};
+	__be32 value;
+	struct snd_kcontrol *ctl;
+	int err;
+
+	err = reg_read(isight, REG_GAIN_RAW_START, &value);
+	if (err < 0)
+		return err;
+	isight->gain_min = be32_to_cpu(value);
+
+	err = reg_read(isight, REG_GAIN_RAW_END, &value);
+	if (err < 0)
+		return err;
+	isight->gain_max = be32_to_cpu(value);
+
+	isight->gain_tlv[0] = SNDRV_CTL_TLVT_DB_MINMAX;
+	isight->gain_tlv[1] = 2 * sizeof(unsigned int);
+
+	err = reg_read(isight, REG_GAIN_DB_START, &value);
+	if (err < 0)
+		return err;
+	isight->gain_tlv[2] = (s32)be32_to_cpu(value) * 100;
+
+	err = reg_read(isight, REG_GAIN_DB_END, &value);
+	if (err < 0)
+		return err;
+	isight->gain_tlv[3] = (s32)be32_to_cpu(value) * 100;
+
+	ctl = snd_ctl_new1(&gain_control, isight);
+	if (ctl)
+		ctl->tlv.p = isight->gain_tlv;
+	err = snd_ctl_add(isight->card, ctl);
+	if (err < 0)
+		return err;
+
+	err = snd_ctl_add(isight->card, snd_ctl_new1(&mute_control, isight));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static void isight_card_free(struct snd_card *card)
+{
+	struct isight *isight = card->private_data;
+
+	fw_iso_resources_destroy(&isight->resources);
+	fw_unit_put(isight->unit);
+	fw_device_put(isight->device);
+	mutex_destroy(&isight->mutex);
+}
+
+static u64 get_unit_base(struct fw_unit *unit)
+{
+	struct fw_csr_iterator i;
+	int key, value;
+
+	fw_csr_iterator_init(&i, unit->directory);
+	while (fw_csr_iterator_next(&i, &key, &value))
+		if (key == CSR_OFFSET)
+			return CSR_REGISTER_BASE + value * 4;
+	return 0;
+}
+
+static int isight_probe(struct device *unit_dev)
+{
+	struct fw_unit *unit = fw_unit(unit_dev);
+	struct fw_device *fw_dev = fw_parent_device(unit);
+	struct snd_card *card;
+	struct isight *isight;
+	int err;
+
+	err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*isight), &card);
+	if (err < 0)
+		return err;
+	snd_card_set_dev(card, unit_dev);
+
+	isight = card->private_data;
+	isight->card = card;
+	mutex_init(&isight->mutex);
+	isight->unit = fw_unit_get(unit);
+	isight->device = fw_device_get(fw_dev);
+	isight->audio_base = get_unit_base(unit);
+	if (!isight->audio_base) {
+		dev_err(&unit->device, "audio unit base not found\n");
+		err = -ENXIO;
+		goto err_unit;
+	}
+	fw_iso_resources_init(&isight->resources, unit);
+
+	card->private_free = isight_card_free;
+
+	strcpy(card->driver, "iSight");
+	strcpy(card->shortname, "Apple iSight");
+	snprintf(card->longname, sizeof(card->longname),
+		 "Apple iSight (GUID %08x%08x) at %s, S%d",
+		 fw_dev->config_rom[3], fw_dev->config_rom[4],
+		 dev_name(&unit->device), 100 << fw_dev->max_speed);
+	strcpy(card->mixername, "iSight");
+
+	err = isight_create_pcm(isight);
+	if (err < 0)
+		goto error;
+
+	err = isight_create_mixer(isight);
+	if (err < 0)
+		goto error;
+
+	err = snd_card_register(card);
+	if (err < 0)
+		goto error;
+
+	dev_set_drvdata(unit_dev, isight);
+
+	return 0;
+
+err_unit:
+	fw_unit_put(isight->unit);
+	fw_device_put(isight->device);
+	mutex_destroy(&isight->mutex);
+error:
+	snd_card_free(card);
+	return err;
+}
+
+static int isight_remove(struct device *dev)
+{
+	struct isight *isight = dev_get_drvdata(dev);
+
+	isight_pcm_abort(isight);
+
+	snd_card_disconnect(isight->card);
+
+	mutex_lock(&isight->mutex);
+	isight_stop_streaming(isight);
+	mutex_unlock(&isight->mutex);
+
+	snd_card_free_when_closed(isight->card);
+
+	return 0;
+}
+
+static void isight_bus_reset(struct fw_unit *unit)
+{
+	struct isight *isight = dev_get_drvdata(&unit->device);
+
+	if (fw_iso_resources_update(&isight->resources) < 0) {
+		isight_pcm_abort(isight);
+
+		mutex_lock(&isight->mutex);
+		isight_stop_streaming(isight);
+		mutex_unlock(&isight->mutex);
+	}
+}
+
+static const struct ieee1394_device_id isight_id_table[] = {
+	{
+		.match_flags  = IEEE1394_MATCH_SPECIFIER_ID |
+				IEEE1394_MATCH_VERSION,
+		.specifier_id = OUI_APPLE,
+		.version      = SW_ISIGHT_AUDIO,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(ieee1394, isight_id_table);
+
+static struct fw_driver isight_driver = {
+	.driver   = {
+		.owner	= THIS_MODULE,
+		.name	= KBUILD_MODNAME,
+		.bus	= &fw_bus_type,
+		.probe	= isight_probe,
+		.remove	= isight_remove,
+	},
+	.update   = isight_bus_reset,
+	.id_table = isight_id_table,
+};
+
+static int __init alsa_isight_init(void)
+{
+	return driver_register(&isight_driver.driver);
+}
+
+static void __exit alsa_isight_exit(void)
+{
+	driver_unregister(&isight_driver.driver);
+}
+
+module_init(alsa_isight_init);
+module_exit(alsa_isight_exit);
diff --git a/sound/firewire/iso-resources.c b/sound/firewire/iso-resources.c
index bb9c0c1fb529..ffe20b877e9f 100644
--- a/sound/firewire/iso-resources.c
+++ b/sound/firewire/iso-resources.c
@@ -31,6 +31,7 @@ int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit)
 
 	return 0;
 }
+EXPORT_SYMBOL(fw_iso_resources_init);
 
 /**
  * fw_iso_resources_destroy - destroy a resource manager
@@ -42,6 +43,7 @@ void fw_iso_resources_destroy(struct fw_iso_resources *r)
 	mutex_destroy(&r->mutex);
 	fw_unit_put(r->unit);
 }
+EXPORT_SYMBOL(fw_iso_resources_destroy);
 
 static unsigned int packet_bandwidth(unsigned int max_payload_bytes, int speed)
 {
@@ -146,6 +148,7 @@ retry_after_bus_reset:
 
 	return channel;
 }
+EXPORT_SYMBOL(fw_iso_resources_allocate);
 
 /**
  * fw_iso_resources_update - update resource allocations after a bus reset
@@ -197,6 +200,7 @@ int fw_iso_resources_update(struct fw_iso_resources *r)
 
 	return channel;
 }
+EXPORT_SYMBOL(fw_iso_resources_update);
 
 /**
  * fw_iso_resources_free - frees allocated resources
@@ -224,3 +228,4 @@ void fw_iso_resources_free(struct fw_iso_resources *r)
 
 	mutex_unlock(&r->mutex);
 }
+EXPORT_SYMBOL(fw_iso_resources_free);
diff --git a/sound/firewire/packets-buffer.c b/sound/firewire/packets-buffer.c
index 1e20e60ba6a6..3c61ca2e6152 100644
--- a/sound/firewire/packets-buffer.c
+++ b/sound/firewire/packets-buffer.c
@@ -60,6 +60,7 @@ err_packets:
 error:
 	return err;
 }
+EXPORT_SYMBOL(iso_packets_buffer_init);
 
 /**
  * iso_packets_buffer_destroy - frees packet buffer resources
@@ -72,3 +73,4 @@ void iso_packets_buffer_destroy(struct iso_packets_buffer *b,
 	fw_iso_buffer_destroy(&b->iso_buffer, fw_parent_device(unit)->card);
 	kfree(b->packets);
 }
+EXPORT_SYMBOL(iso_packets_buffer_destroy);
diff --git a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile
index 2dad40f3f622..c95d8f1aae87 100644
--- a/sound/i2c/other/Makefile
+++ b/sound/i2c/other/Makefile
@@ -14,4 +14,4 @@ snd-tea575x-tuner-objs := tea575x-tuner.o
 obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o
 obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o
 obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4113.o snd-ak4xxx-adda.o snd-pt2258.o
-obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o
+obj-$(CONFIG_SND_TEA575X) += snd-tea575x-tuner.o
diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c
index ee538f1ae846..4831800239d3 100644
--- a/sound/i2c/other/tea575x-tuner.c
+++ b/sound/i2c/other/tea575x-tuner.c
@@ -37,8 +37,8 @@ static int radio_nr = -1;
 module_param(radio_nr, int, 0);
 
 #define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-#define FREQ_LO		 (87 * 16000)
-#define FREQ_HI		(108 * 16000)
+#define FREQ_LO		 (50UL * 16000)
+#define FREQ_HI		(150UL * 16000)
 
 /*
  * definitions
@@ -77,27 +77,95 @@ static struct v4l2_queryctrl radio_qctrl[] = {
  * lowlevel part
  */
 
+static void snd_tea575x_write(struct snd_tea575x *tea, unsigned int val)
+{
+	u16 l;
+	u8 data;
+
+	tea->ops->set_direction(tea, 1);
+	udelay(16);
+
+	for (l = 25; l > 0; l--) {
+		data = (val >> 24) & TEA575X_DATA;
+		val <<= 1;			/* shift data */
+		tea->ops->set_pins(tea, data | TEA575X_WREN);
+		udelay(2);
+		tea->ops->set_pins(tea, data | TEA575X_WREN | TEA575X_CLK);
+		udelay(2);
+		tea->ops->set_pins(tea, data | TEA575X_WREN);
+		udelay(2);
+	}
+
+	if (!tea->mute)
+		tea->ops->set_pins(tea, 0);
+}
+
+static unsigned int snd_tea575x_read(struct snd_tea575x *tea)
+{
+	u16 l, rdata;
+	u32 data = 0;
+
+	tea->ops->set_direction(tea, 0);
+	tea->ops->set_pins(tea, 0);
+	udelay(16);
+
+	for (l = 24; l--;) {
+		tea->ops->set_pins(tea, TEA575X_CLK);
+		udelay(2);
+		if (!l)
+			tea->tuned = tea->ops->get_pins(tea) & TEA575X_MOST ? 0 : 1;
+		tea->ops->set_pins(tea, 0);
+		udelay(2);
+		data <<= 1;			/* shift data */
+		rdata = tea->ops->get_pins(tea);
+		if (!l)
+			tea->stereo = (rdata & TEA575X_MOST) ?  0 : 1;
+		if (rdata & TEA575X_DATA)
+			data++;
+		udelay(2);
+	}
+
+	if (tea->mute)
+		tea->ops->set_pins(tea, TEA575X_WREN);
+
+	return data;
+}
+
+static void snd_tea575x_get_freq(struct snd_tea575x *tea)
+{
+	unsigned long freq;
+
+	freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK;
+	/* freq *= 12.5 */
+	freq *= 125;
+	freq /= 10;
+	/* crystal fixup */
+	if (tea->tea5759)
+		freq += TEA575X_FMIF;
+	else
+		freq -= TEA575X_FMIF;
+
+	tea->freq = freq * 16;		/* from kHz */
+}
+
 static void snd_tea575x_set_freq(struct snd_tea575x *tea)
 {
 	unsigned long freq;
 
-	freq = tea->freq / 16;		/* to kHz */
-	if (freq > 108000)
-		freq = 108000;
-	if (freq < 87000)
-		freq = 87000;
+	freq = clamp(tea->freq, FREQ_LO, FREQ_HI);
+	freq /= 16;		/* to kHz */
 	/* crystal fixup */
 	if (tea->tea5759)
-		freq -= tea->freq_fixup;
+		freq -= TEA575X_FMIF;
 	else
-		freq += tea->freq_fixup;
+		freq += TEA575X_FMIF;
 	/* freq /= 12.5 */
 	freq *= 10;
 	freq /= 125;
 
 	tea->val &= ~TEA575X_BIT_FREQ_MASK;
 	tea->val |= freq & TEA575X_BIT_FREQ_MASK;
-	tea->ops->write(tea, tea->val);
+	snd_tea575x_write(tea, tea->val);
 }
 
 /*
@@ -109,29 +177,34 @@ static int vidioc_querycap(struct file *file, void  *priv,
 {
 	struct snd_tea575x *tea = video_drvdata(file);
 
-	strcpy(v->card, tea->tea5759 ? "TEA5759" : "TEA5757");
 	strlcpy(v->driver, "tea575x-tuner", sizeof(v->driver));
-	strlcpy(v->card, "Maestro Radio", sizeof(v->card));
-	sprintf(v->bus_info, "PCI");
+	strlcpy(v->card, tea->card, sizeof(v->card));
+	strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card));
+	strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info));
 	v->version = RADIO_VERSION;
-	v->capabilities = V4L2_CAP_TUNER;
+	v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
 	return 0;
 }
 
 static int vidioc_g_tuner(struct file *file, void *priv,
 					struct v4l2_tuner *v)
 {
+	struct snd_tea575x *tea = video_drvdata(file);
+
 	if (v->index > 0)
 		return -EINVAL;
 
+	snd_tea575x_read(tea);
+
 	strcpy(v->name, "FM");
 	v->type = V4L2_TUNER_RADIO;
+	v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
 	v->rangelow = FREQ_LO;
 	v->rangehigh = FREQ_HI;
-	v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
-	v->capability = V4L2_TUNER_CAP_LOW;
-	v->audmode = V4L2_TUNER_MODE_MONO;
-	v->signal = 0xffff;
+	v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+	v->audmode = tea->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO;
+	v->signal = tea->tuned ? 0xffff : 0;
+
 	return 0;
 }
 
@@ -148,7 +221,10 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 {
 	struct snd_tea575x *tea = video_drvdata(file);
 
+	if (f->tuner != 0)
+		return -EINVAL;
 	f->type = V4L2_TUNER_RADIO;
+	snd_tea575x_get_freq(tea);
 	f->frequency = tea->freq;
 	return 0;
 }
@@ -158,6 +234,9 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
 	struct snd_tea575x *tea = video_drvdata(file);
 
+	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
+
 	if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
 		return -EINVAL;
 
@@ -209,10 +288,8 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
-		if (tea->ops->mute) {
-			ctrl->value = tea->mute;
-			return 0;
-		}
+		ctrl->value = tea->mute;
+		return 0;
 	}
 	return -EINVAL;
 }
@@ -224,11 +301,11 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
-		if (tea->ops->mute) {
-			tea->ops->mute(tea, ctrl->value);
+		if (tea->mute != ctrl->value) {
 			tea->mute = ctrl->value;
-			return 0;
+			snd_tea575x_set_freq(tea);
 		}
+		return 0;
 	}
 	return -EINVAL;
 }
@@ -293,18 +370,16 @@ static struct video_device tea575x_radio = {
 /*
  * initialize all the tea575x chips
  */
-void snd_tea575x_init(struct snd_tea575x *tea)
+int snd_tea575x_init(struct snd_tea575x *tea)
 {
 	int retval;
-	unsigned int val;
 	struct video_device *tea575x_radio_inst;
 
-	val = tea->ops->read(tea);
-	if (val == 0x1ffffff || val == 0) {
-		snd_printk(KERN_ERR
-			   "tea575x-tuner: Cannot find TEA575x chip\n");
-		return;
-	}
+	tea->mute = 1;
+
+	snd_tea575x_write(tea, 0x55AA);
+	if (snd_tea575x_read(tea) != 0x55AA)
+		return -ENODEV;
 
 	tea->in_use = 0;
 	tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40;
@@ -313,7 +388,7 @@ void snd_tea575x_init(struct snd_tea575x *tea)
 	tea575x_radio_inst = video_device_alloc();
 	if (tea575x_radio_inst == NULL) {
 		printk(KERN_ERR "tea575x-tuner: not enough memory\n");
-		return;
+		return -ENOMEM;
 	}
 
 	memcpy(tea575x_radio_inst, &tea575x_radio, sizeof(tea575x_radio));
@@ -328,17 +403,13 @@ void snd_tea575x_init(struct snd_tea575x *tea)
 	if (retval) {
 		printk(KERN_ERR "tea575x-tuner: can't register video device!\n");
 		kfree(tea575x_radio_inst);
-		return;
+		return retval;
 	}
 
 	snd_tea575x_set_freq(tea);
-
-	/* mute on init */
-	if (tea->ops->mute) {
-		tea->ops->mute(tea, 1);
-		tea->mute = 1;
-	}
 	tea->vd = tea575x_radio_inst;
+
+	return 0;
 }
 
 void snd_tea575x_exit(struct snd_tea575x *tea)
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index 76c090218073..6c93e051f9ae 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -22,10 +22,6 @@ config SOUND_VWSND
 	  <file:Documentation/sound/oss/vwsnd> for more info on this driver's
 	  capabilities.
 
-config SOUND_AU1550_AC97
-	tristate "Au1550/Au1200 AC97 Sound"
-	depends on SOC_AU1550 || SOC_AU1200
-
 config SOUND_MSNDCLAS
 	tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey"
 	depends on (m || !STANDALONE) && ISA
diff --git a/sound/oss/Makefile b/sound/oss/Makefile
index 90ffb99c6b17..77f21b68bf0f 100644
--- a/sound/oss/Makefile
+++ b/sound/oss/Makefile
@@ -25,7 +25,6 @@ obj-$(CONFIG_SOUND_WAVEARTIST)	+= waveartist.o
 obj-$(CONFIG_SOUND_MSNDCLAS)	+= msnd.o msnd_classic.o
 obj-$(CONFIG_SOUND_MSNDPIN)	+= msnd.o msnd_pinnacle.o
 obj-$(CONFIG_SOUND_VWSND)	+= vwsnd.o
-obj-$(CONFIG_SOUND_AU1550_AC97)	+= au1550_ac97.o ac97_codec.o
 obj-$(CONFIG_SOUND_BCM_CS4297A)	+= swarm_cs4297a.o
 
 obj-$(CONFIG_DMASOUND)		+= dmasound/
diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c
deleted file mode 100644
index 0cd23d94888f..000000000000
--- a/sound/oss/ac97_codec.c
+++ /dev/null
@@ -1,1203 +0,0 @@
-/*
- * ac97_codec.c: Generic AC97 mixer/modem module
- *
- * Derived from ac97 mixer in maestro and trident driver.
- *
- * Copyright 2000 Silicon Integrated System Corporation
- *
- *	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, write to the Free Software
- *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- **************************************************************************
- *
- * The Intel Audio Codec '97 specification is available at:
- * http://download.intel.com/support/motherboards/desktop/sb/ac97_r23.pdf
- *
- **************************************************************************
- *
- * History
- * May 02, 2003 Liam Girdwood <lrg@slimlogic.co.uk>
- *	Removed non existent WM9700
- *	Added support for WM9705, WM9708, WM9709, WM9710, WM9711
- *	WM9712 and WM9717
- * Mar 28, 2002 Randolph Bentson <bentson@holmsjoen.com>
- *	corrections to support WM9707 in ViewPad 1000
- * v0.4 Mar 15 2000 Ollie Lho
- *	dual codecs support verified with 4 channels output
- * v0.3 Feb 22 2000 Ollie Lho
- *	bug fix for record mask setting
- * v0.2 Feb 10 2000 Ollie Lho
- *	add ac97_read_proc for /proc/driver/{vendor}/ac97
- * v0.1 Jan 14 2000 Ollie Lho <ollie@sis.com.tw> 
- *	Isolated from trident.c to support multiple ac97 codec
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/ac97_codec.h>
-#include <asm/uaccess.h>
-#include <linux/mutex.h>
-
-#define CODEC_ID_BUFSZ 14
-
-static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel);
-static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel, 
-			     unsigned int left, unsigned int right);
-static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val );
-static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask);
-static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg);
-
-static int ac97_init_mixer(struct ac97_codec *codec);
-
-static int wolfson_init03(struct ac97_codec * codec);
-static int wolfson_init04(struct ac97_codec * codec);
-static int wolfson_init05(struct ac97_codec * codec);
-static int wolfson_init11(struct ac97_codec * codec);
-static int wolfson_init13(struct ac97_codec * codec);
-static int tritech_init(struct ac97_codec * codec);
-static int tritech_maestro_init(struct ac97_codec * codec);
-static int sigmatel_9708_init(struct ac97_codec *codec);
-static int sigmatel_9721_init(struct ac97_codec *codec);
-static int sigmatel_9744_init(struct ac97_codec *codec);
-static int ad1886_init(struct ac97_codec *codec);
-static int eapd_control(struct ac97_codec *codec, int);
-static int crystal_digital_control(struct ac97_codec *codec, int slots, int rate, int mode);
-static int cmedia_init(struct ac97_codec * codec);
-static int cmedia_digital_control(struct ac97_codec *codec, int slots, int rate, int mode);
-static int generic_digital_control(struct ac97_codec *codec, int slots, int rate, int mode);
-
-
-/*
- *	AC97 operations.
- *
- *	If you are adding a codec then you should be able to use
- *		eapd_ops - any codec that supports EAPD amp control (most)
- *		null_ops - any ancient codec that supports nothing
- *
- *	The three functions are
- *		init - used for non AC97 standard initialisation
- *		amplifier - used to do amplifier control (1=on 0=off)
- *		digital - switch to digital modes (0 = analog)
- *
- *	Not all codecs support all features, not all drivers use all the
- *	operations yet
- */
- 
-static struct ac97_ops null_ops = { NULL, NULL, NULL };
-static struct ac97_ops default_ops = { NULL, eapd_control, NULL };
-static struct ac97_ops default_digital_ops = { NULL, eapd_control, generic_digital_control};
-static struct ac97_ops wolfson_ops03 = { wolfson_init03, NULL, NULL };
-static struct ac97_ops wolfson_ops04 = { wolfson_init04, NULL, NULL };
-static struct ac97_ops wolfson_ops05 = { wolfson_init05, NULL, NULL };
-static struct ac97_ops wolfson_ops11 = { wolfson_init11, NULL, NULL };
-static struct ac97_ops wolfson_ops13 = { wolfson_init13, NULL, NULL };
-static struct ac97_ops tritech_ops = { tritech_init, NULL, NULL };
-static struct ac97_ops tritech_m_ops = { tritech_maestro_init, NULL, NULL };
-static struct ac97_ops sigmatel_9708_ops = { sigmatel_9708_init, NULL, NULL };
-static struct ac97_ops sigmatel_9721_ops = { sigmatel_9721_init, NULL, NULL };
-static struct ac97_ops sigmatel_9744_ops = { sigmatel_9744_init, NULL, NULL };
-static struct ac97_ops crystal_digital_ops = { NULL, eapd_control, crystal_digital_control };
-static struct ac97_ops ad1886_ops = { ad1886_init, eapd_control, NULL };
-static struct ac97_ops cmedia_ops = { NULL, eapd_control, NULL};
-static struct ac97_ops cmedia_digital_ops = { cmedia_init, eapd_control, cmedia_digital_control};
-
-/* sorted by vendor/device id */
-static const struct {
-	u32 id;
-	char *name;
-	struct ac97_ops *ops;
-	int flags;
-} ac97_codec_ids[] = {
-	{0x41445303, "Analog Devices AD1819",	&null_ops},
-	{0x41445340, "Analog Devices AD1881",	&null_ops},
-	{0x41445348, "Analog Devices AD1881A",	&null_ops},
-	{0x41445360, "Analog Devices AD1885",	&default_ops},
-	{0x41445361, "Analog Devices AD1886",	&ad1886_ops},
-	{0x41445370, "Analog Devices AD1981",	&null_ops},
-	{0x41445372, "Analog Devices AD1981A",	&null_ops},
-	{0x41445374, "Analog Devices AD1981B",	&null_ops},
-	{0x41445460, "Analog Devices AD1885",	&default_ops},
-	{0x41445461, "Analog Devices AD1886",	&ad1886_ops},
-	{0x414B4D00, "Asahi Kasei AK4540",	&null_ops},
-	{0x414B4D01, "Asahi Kasei AK4542",	&null_ops},
-	{0x414B4D02, "Asahi Kasei AK4543",	&null_ops},
-	{0x414C4326, "ALC100P",			&null_ops},
-	{0x414C4710, "ALC200/200P",		&null_ops},
-	{0x414C4720, "ALC650",			&default_digital_ops},
-	{0x434D4941, "CMedia",			&cmedia_ops,		AC97_NO_PCM_VOLUME },
-	{0x434D4942, "CMedia",			&cmedia_ops,		AC97_NO_PCM_VOLUME },
-	{0x434D4961, "CMedia",			&cmedia_digital_ops,	AC97_NO_PCM_VOLUME },
-	{0x43525900, "Cirrus Logic CS4297",	&default_ops},
-	{0x43525903, "Cirrus Logic CS4297",	&default_ops},
-	{0x43525913, "Cirrus Logic CS4297A rev A", &default_ops},
-	{0x43525914, "Cirrus Logic CS4297A rev B", &default_ops},
-	{0x43525923, "Cirrus Logic CS4298",	&null_ops},
-	{0x4352592B, "Cirrus Logic CS4294",	&null_ops},
-	{0x4352592D, "Cirrus Logic CS4294",	&null_ops},
-	{0x43525931, "Cirrus Logic CS4299 rev A", &crystal_digital_ops},
-	{0x43525933, "Cirrus Logic CS4299 rev C", &crystal_digital_ops},
-	{0x43525934, "Cirrus Logic CS4299 rev D", &crystal_digital_ops},
-	{0x43585430, "CXT48",			&default_ops,		AC97_DELUDED_MODEM },
-	{0x43585442, "CXT66",			&default_ops,		AC97_DELUDED_MODEM },
-	{0x44543031, "Diamond Technology DT0893", &default_ops},
-	{0x45838308, "ESS Allegro ES1988",	&null_ops},
-	{0x49434511, "ICE1232",			&null_ops}, /* I hope --jk */
-	{0x4e534331, "National Semiconductor LM4549", &null_ops},
-	{0x53494c22, "Silicon Laboratory Si3036", &null_ops},
-	{0x53494c23, "Silicon Laboratory Si3038", &null_ops},
-	{0x545200FF, "TriTech TR?????",		&tritech_m_ops},
-	{0x54524102, "TriTech TR28022",		&null_ops},
-	{0x54524103, "TriTech TR28023",		&null_ops},
-	{0x54524106, "TriTech TR28026",		&null_ops},
-	{0x54524108, "TriTech TR28028",		&tritech_ops},
-	{0x54524123, "TriTech TR A5",		&null_ops},
-	{0x574D4C03, "Wolfson WM9703/07/08/17",	&wolfson_ops03},
-	{0x574D4C04, "Wolfson WM9704M/WM9704Q",	&wolfson_ops04},
-	{0x574D4C05, "Wolfson WM9705/WM9710",   &wolfson_ops05},
-	{0x574D4C09, "Wolfson WM9709",		&null_ops},
-	{0x574D4C12, "Wolfson WM9711/9712",	&wolfson_ops11},
-	{0x574D4C13, "Wolfson WM9713",	&wolfson_ops13, AC97_DEFAULT_POWER_OFF},
-	{0x83847600, "SigmaTel STAC????",	&null_ops},
-	{0x83847604, "SigmaTel STAC9701/3/4/5", &null_ops},
-	{0x83847605, "SigmaTel STAC9704",	&null_ops},
-	{0x83847608, "SigmaTel STAC9708",	&sigmatel_9708_ops},
-	{0x83847609, "SigmaTel STAC9721/23",	&sigmatel_9721_ops},
-	{0x83847644, "SigmaTel STAC9744/45",	&sigmatel_9744_ops},
-	{0x83847652, "SigmaTel STAC9752/53",	&default_ops},
-	{0x83847656, "SigmaTel STAC9756/57",	&sigmatel_9744_ops},
-	{0x83847666, "SigmaTel STAC9750T",	&sigmatel_9744_ops},
-	{0x83847684, "SigmaTel STAC9783/84?",	&null_ops},
-	{0x57454301, "Winbond 83971D",		&null_ops},
-};
-
-/* this table has default mixer values for all OSS mixers. */
-static struct mixer_defaults {
-	int mixer;
-	unsigned int value;
-} mixer_defaults[SOUND_MIXER_NRDEVICES] = {
-	/* all values 0 -> 100 in bytes */
-	{SOUND_MIXER_VOLUME,	0x4343},
-	{SOUND_MIXER_BASS,	0x4343},
-	{SOUND_MIXER_TREBLE,	0x4343},
-	{SOUND_MIXER_PCM,	0x4343},
-	{SOUND_MIXER_SPEAKER,	0x4343},
-	{SOUND_MIXER_LINE,	0x4343},
-	{SOUND_MIXER_MIC,	0x0000},
-	{SOUND_MIXER_CD,	0x4343},
-	{SOUND_MIXER_ALTPCM,	0x4343},
-	{SOUND_MIXER_IGAIN,	0x4343},
-	{SOUND_MIXER_LINE1,	0x4343},
-	{SOUND_MIXER_PHONEIN,	0x4343},
-	{SOUND_MIXER_PHONEOUT,	0x4343},
-	{SOUND_MIXER_VIDEO,	0x4343},
-	{-1,0}
-};
-
-/* table to scale scale from OSS mixer value to AC97 mixer register value */	
-static struct ac97_mixer_hw {
-	unsigned char offset;
-	int scale;
-} ac97_hw[SOUND_MIXER_NRDEVICES]= {
-	[SOUND_MIXER_VOLUME]	=	{AC97_MASTER_VOL_STEREO,64},
-	[SOUND_MIXER_BASS]	=	{AC97_MASTER_TONE,	16},
-	[SOUND_MIXER_TREBLE]	=	{AC97_MASTER_TONE,	16},
-	[SOUND_MIXER_PCM]	=	{AC97_PCMOUT_VOL,	32},
-	[SOUND_MIXER_SPEAKER]	=	{AC97_PCBEEP_VOL,	16},
-	[SOUND_MIXER_LINE]	=	{AC97_LINEIN_VOL,	32},
-	[SOUND_MIXER_MIC]	=	{AC97_MIC_VOL,		32},
-	[SOUND_MIXER_CD]	=	{AC97_CD_VOL,		32},
-	[SOUND_MIXER_ALTPCM]	=	{AC97_HEADPHONE_VOL,	64},
-	[SOUND_MIXER_IGAIN]	=	{AC97_RECORD_GAIN,	16},
-	[SOUND_MIXER_LINE1]	=	{AC97_AUX_VOL,		32},
-	[SOUND_MIXER_PHONEIN]	= 	{AC97_PHONE_VOL,	32},
-	[SOUND_MIXER_PHONEOUT]	= 	{AC97_MASTER_VOL_MONO,	64},
-	[SOUND_MIXER_VIDEO]	=	{AC97_VIDEO_VOL,	32},
-};
-
-/* the following tables allow us to go from OSS <-> ac97 quickly. */
-enum ac97_recsettings {
-	AC97_REC_MIC=0,
-	AC97_REC_CD,
-	AC97_REC_VIDEO,
-	AC97_REC_AUX,
-	AC97_REC_LINE,
-	AC97_REC_STEREO, /* combination of all enabled outputs..  */
-	AC97_REC_MONO,	      /*.. or the mono equivalent */
-	AC97_REC_PHONE
-};
-
-static const unsigned int ac97_rm2oss[] = {
-	[AC97_REC_MIC] 	 = SOUND_MIXER_MIC,
-	[AC97_REC_CD] 	 = SOUND_MIXER_CD,
-	[AC97_REC_VIDEO] = SOUND_MIXER_VIDEO,
-	[AC97_REC_AUX] 	 = SOUND_MIXER_LINE1,
-	[AC97_REC_LINE]  = SOUND_MIXER_LINE,
-	[AC97_REC_STEREO]= SOUND_MIXER_IGAIN,
-	[AC97_REC_PHONE] = SOUND_MIXER_PHONEIN
-};
-
-/* indexed by bit position */
-static const unsigned int ac97_oss_rm[] = {
-	[SOUND_MIXER_MIC] 	= AC97_REC_MIC,
-	[SOUND_MIXER_CD] 	= AC97_REC_CD,
-	[SOUND_MIXER_VIDEO] 	= AC97_REC_VIDEO,
-	[SOUND_MIXER_LINE1] 	= AC97_REC_AUX,
-	[SOUND_MIXER_LINE] 	= AC97_REC_LINE,
-	[SOUND_MIXER_IGAIN]	= AC97_REC_STEREO,
-	[SOUND_MIXER_PHONEIN] 	= AC97_REC_PHONE
-};
-
-static LIST_HEAD(codecs);
-static LIST_HEAD(codec_drivers);
-static DEFINE_MUTEX(codec_mutex);
-
-/* reads the given OSS mixer from the ac97 the caller must have insured that the ac97 knows
-   about that given mixer, and should be holding a spinlock for the card */
-static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel) 
-{
-	u16 val;
-	int ret = 0;
-	int scale;
-	struct ac97_mixer_hw *mh = &ac97_hw[oss_channel];
-
-	val = codec->codec_read(codec , mh->offset);
-
-	if (val & AC97_MUTE) {
-		ret = 0;
-	} else if (AC97_STEREO_MASK & (1 << oss_channel)) {
-		/* nice stereo mixers .. */
-		int left,right;
-
-		left = (val >> 8)  & 0x7f;
-		right = val  & 0x7f;
-
-		if (oss_channel == SOUND_MIXER_IGAIN) {
-			right = (right * 100) / mh->scale;
-			left = (left * 100) / mh->scale;
-		} else {
-			/* these may have 5 or 6 bit resolution */
-			if(oss_channel == SOUND_MIXER_VOLUME || oss_channel == SOUND_MIXER_ALTPCM)
-				scale = (1 << codec->bit_resolution);
-			else
-				scale = mh->scale;
-
-			right = 100 - ((right * 100) / scale);
-			left = 100 - ((left * 100) / scale);
-		}
-		ret = left | (right << 8);
-	} else if (oss_channel == SOUND_MIXER_SPEAKER) {
-		ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale);
-	} else if (oss_channel == SOUND_MIXER_PHONEIN) {
-		ret = 100 - (((val & 0x1f) * 100) / mh->scale);
-	} else if (oss_channel == SOUND_MIXER_PHONEOUT) {
-		scale = (1 << codec->bit_resolution);
-		ret = 100 - (((val & 0x1f) * 100) / scale);
-	} else if (oss_channel == SOUND_MIXER_MIC) {
-		ret = 100 - (((val & 0x1f) * 100) / mh->scale);
-		/*  the low bit is optional in the tone sliders and masking
-		    it lets us avoid the 0xf 'bypass'.. */
-	} else if (oss_channel == SOUND_MIXER_BASS) {
-		ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale);
-	} else if (oss_channel == SOUND_MIXER_TREBLE) {
-		ret = 100 - (((val & 0xe) * 100) / mh->scale);
-	}
-
-#ifdef DEBUG
-	printk("ac97_codec: read OSS mixer %2d (%s ac97 register 0x%02x), "
-	       "0x%04x -> 0x%04x\n",
-	       oss_channel, codec->id ? "Secondary" : "Primary",
-	       mh->offset, val, ret);
-#endif
-
-	return ret;
-}
-
-/* write the OSS encoded volume to the given OSS encoded mixer, again caller's job to
-   make sure all is well in arg land, call with spinlock held */
-static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel,
-		      unsigned int left, unsigned int right)
-{
-	u16 val = 0;
-	int scale;
-	struct ac97_mixer_hw *mh = &ac97_hw[oss_channel];
-
-#ifdef DEBUG
-	printk("ac97_codec: wrote OSS mixer %2d (%s ac97 register 0x%02x), "
-	       "left vol:%2d, right vol:%2d:",
-	       oss_channel, codec->id ? "Secondary" : "Primary",
-	       mh->offset, left, right);
-#endif
-
-	if (AC97_STEREO_MASK & (1 << oss_channel)) {
-		/* stereo mixers */
-		if (left == 0 && right == 0) {
-			val = AC97_MUTE;
-		} else {
-			if (oss_channel == SOUND_MIXER_IGAIN) {
-				right = (right * mh->scale) / 100;
-				left = (left * mh->scale) / 100;
-				if (right >= mh->scale)
-					right = mh->scale-1;
-				if (left >= mh->scale)
-					left = mh->scale-1;
-			} else {
-				/* these may have 5 or 6 bit resolution */
-				if (oss_channel == SOUND_MIXER_VOLUME ||
-				    oss_channel == SOUND_MIXER_ALTPCM)
-					scale = (1 << codec->bit_resolution);
-				else
-					scale = mh->scale;
-
-				right = ((100 - right) * scale) / 100;
-				left = ((100 - left) * scale) / 100;
-				if (right >= scale)
-					right = scale-1;
-				if (left >= scale)
-					left = scale-1;
-			}
-			val = (left << 8) | right;
-		}
-	} else if (oss_channel == SOUND_MIXER_BASS) {
-		val = codec->codec_read(codec , mh->offset) & ~0x0f00;
-		left = ((100 - left) * mh->scale) / 100;
-		if (left >= mh->scale)
-			left = mh->scale-1;
-		val |= (left << 8) & 0x0e00;
-	} else if (oss_channel == SOUND_MIXER_TREBLE) {
-		val = codec->codec_read(codec , mh->offset) & ~0x000f;
-		left = ((100 - left) * mh->scale) / 100;
-		if (left >= mh->scale)
-			left = mh->scale-1;
-		val |= left & 0x000e;
-	} else if(left == 0) {
-		val = AC97_MUTE;
-	} else if (oss_channel == SOUND_MIXER_SPEAKER) {
-		left = ((100 - left) * mh->scale) / 100;
-		if (left >= mh->scale)
-			left = mh->scale-1;
-		val = left << 1;
-	} else if (oss_channel == SOUND_MIXER_PHONEIN) {
-		left = ((100 - left) * mh->scale) / 100;
-		if (left >= mh->scale)
-			left = mh->scale-1;
-		val = left;
-	} else if (oss_channel == SOUND_MIXER_PHONEOUT) {
-		scale = (1 << codec->bit_resolution);
-		left = ((100 - left) * scale) / 100;
-		if (left >= mh->scale)
-			left = mh->scale-1;
-		val = left;
-	} else if (oss_channel == SOUND_MIXER_MIC) {
-		val = codec->codec_read(codec , mh->offset) & ~0x801f;
-		left = ((100 - left) * mh->scale) / 100;
-		if (left >= mh->scale)
-			left = mh->scale-1;
-		val |= left;
-		/*  the low bit is optional in the tone sliders and masking
-		    it lets us avoid the 0xf 'bypass'.. */
-	}
-#ifdef DEBUG
-	printk(" 0x%04x", val);
-#endif
-
-	codec->codec_write(codec, mh->offset, val);
-
-#ifdef DEBUG
-	val = codec->codec_read(codec, mh->offset);
-	printk(" -> 0x%04x\n", val);
-#endif
-}
-
-/* a thin wrapper for write_mixer */
-static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val ) 
-{
-	unsigned int left,right;
-
-	/* cleanse input a little */
-	right = ((val >> 8)  & 0xff) ;
-	left = (val  & 0xff) ;
-
-	if (right > 100) right = 100;
-	if (left > 100) left = 100;
-
-	codec->mixer_state[oss_mixer] = (right << 8) | left;
-	codec->write_mixer(codec, oss_mixer, left, right);
-}
-
-/* read or write the recmask, the ac97 can really have left and right recording
-   inputs independently set, but OSS doesn't seem to want us to express that to
-   the user. the caller guarantees that we have a supported bit set, and they
-   must be holding the card's spinlock */
-static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask) 
-{
-	unsigned int val;
-
-	if (rw) {
-		/* read it from the card */
-		val = codec->codec_read(codec, AC97_RECORD_SELECT);
-#ifdef DEBUG
-		printk("ac97_codec: ac97 recmask to set to 0x%04x\n", val);
-#endif
-		return (1 << ac97_rm2oss[val & 0x07]);
-	}
-
-	/* else, write the first set in the mask as the
-	   output */	
-	/* clear out current set value first (AC97 supports only 1 input!) */
-	val = (1 << ac97_rm2oss[codec->codec_read(codec, AC97_RECORD_SELECT) & 0x07]);
-	if (mask != val)
-	    mask &= ~val;
-       
-	val = ffs(mask); 
-	val = ac97_oss_rm[val-1];
-	val |= val << 8;  /* set both channels */
-
-#ifdef DEBUG
-	printk("ac97_codec: setting ac97 recmask to 0x%04x\n", val);
-#endif
-
-	codec->codec_write(codec, AC97_RECORD_SELECT, val);
-
-	return 0;
-};
-
-static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg)
-{
-	int i, val = 0;
-
-	if (cmd == SOUND_MIXER_INFO) {
-		mixer_info info;
-		memset(&info, 0, sizeof(info));
-		strlcpy(info.id, codec->name, sizeof(info.id));
-		strlcpy(info.name, codec->name, sizeof(info.name));
-		info.modify_counter = codec->modcnt;
-		if (copy_to_user((void __user *)arg, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	if (cmd == SOUND_OLD_MIXER_INFO) {
-		_old_mixer_info info;
-		memset(&info, 0, sizeof(info));
-		strlcpy(info.id, codec->name, sizeof(info.id));
-		strlcpy(info.name, codec->name, sizeof(info.name));
-		if (copy_to_user((void __user *)arg, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-
-	if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
-		return -EINVAL;
-
-	if (cmd == OSS_GETVERSION)
-		return put_user(SOUND_VERSION, (int __user *)arg);
-
-	if (_SIOC_DIR(cmd) == _SIOC_READ) {
-		switch (_IOC_NR(cmd)) {
-		case SOUND_MIXER_RECSRC: /* give them the current record source */
-			if (!codec->recmask_io) {
-				val = 0;
-			} else {
-				val = codec->recmask_io(codec, 1, 0);
-			}
-			break;
-
-		case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
-			val = codec->supported_mixers;
-			break;
-
-		case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
-			val = codec->record_sources;
-			break;
-
-		case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
-			val = codec->stereo_mixers;
-			break;
-
-		case SOUND_MIXER_CAPS:
-			val = SOUND_CAP_EXCL_INPUT;
-			break;
-
-		default: /* read a specific mixer */
-			i = _IOC_NR(cmd);
-
-			if (!supported_mixer(codec, i)) 
-				return -EINVAL;
-
-			/* do we ever want to touch the hardware? */
-		        /* val = codec->read_mixer(codec, i); */
-			val = codec->mixer_state[i];
- 			break;
-		}
-		return put_user(val, (int __user *)arg);
-	}
-
-	if (_SIOC_DIR(cmd) == (_SIOC_WRITE|_SIOC_READ)) {
-		codec->modcnt++;
-		if (get_user(val, (int __user *)arg))
-			return -EFAULT;
-
-		switch (_IOC_NR(cmd)) {
-		case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-			if (!codec->recmask_io) return -EINVAL;
-			if (!val) return 0;
-			if (!(val &= codec->record_sources)) return -EINVAL;
-
-			codec->recmask_io(codec, 0, val);
-
-			return 0;
-		default: /* write a specific mixer */
-			i = _IOC_NR(cmd);
-
-			if (!supported_mixer(codec, i)) 
-				return -EINVAL;
-
-			ac97_set_mixer(codec, i, val);
-
-			return 0;
-		}
-	}
-	return -EINVAL;
-}
-
-/**
- *	codec_id	-  Turn id1/id2 into a PnP string
- *	@id1: Vendor ID1
- *	@id2: Vendor ID2
- *	@buf: CODEC_ID_BUFSZ byte buffer
- *
- *	Fills buf with a zero terminated PnP ident string for the id1/id2
- *	pair. For convenience the return is the passed in buffer pointer.
- */
- 
-static char *codec_id(u16 id1, u16 id2, char *buf)
-{
-	if(id1&0x8080) {
-		snprintf(buf, CODEC_ID_BUFSZ, "0x%04x:0x%04x", id1, id2);
-	} else {
-		buf[0] = (id1 >> 8);
-		buf[1] = (id1 & 0xFF);
-		buf[2] = (id2 >> 8);
-		snprintf(buf+3, CODEC_ID_BUFSZ - 3, "%d", id2&0xFF);
-	}
-	return buf;
-}
- 
-/**
- *	ac97_check_modem - Check if the Codec is a modem
- *	@codec: codec to check
- *
- *	Return true if the device is an AC97 1.0 or AC97 2.0 modem
- */
- 
-static int ac97_check_modem(struct ac97_codec *codec)
-{
-	/* Check for an AC97 1.0 soft modem (ID1) */
-	if(codec->codec_read(codec, AC97_RESET) & 2)
-		return 1;
-	/* Check for an AC97 2.x soft modem */
-	codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0L);
-	if(codec->codec_read(codec, AC97_EXTENDED_MODEM_ID) & 1)
-		return 1;
-	return 0;
-}
-
-
-/**
- *	ac97_alloc_codec - Allocate an AC97 codec
- *
- *	Returns a new AC97 codec structure. AC97 codecs may become
- *	refcounted soon so this interface is needed. Returns with
- *	one reference taken.
- */
- 
-struct ac97_codec *ac97_alloc_codec(void)
-{
-	struct ac97_codec *codec = kzalloc(sizeof(struct ac97_codec), GFP_KERNEL);
-	if(!codec)
-		return NULL;
-
-	spin_lock_init(&codec->lock);
-	INIT_LIST_HEAD(&codec->list);
-	return codec;
-}
-
-EXPORT_SYMBOL(ac97_alloc_codec);
-
-/**
- *	ac97_release_codec -	Release an AC97 codec
- *	@codec: codec to release
- *
- *	Release an allocated AC97 codec. This will be refcounted in
- *	time but for the moment is trivial. Calls the unregister
- *	handler if the codec is now defunct.
- */
- 
-void ac97_release_codec(struct ac97_codec *codec)
-{
-	/* Remove from the list first, we don't want to be
-	   "rediscovered" */
-	mutex_lock(&codec_mutex);
-	list_del(&codec->list);
-	mutex_unlock(&codec_mutex);
-	/*
-	 *	The driver needs to deal with internal
-	 *	locking to avoid accidents here. 
-	 */
-	if(codec->driver)
-		codec->driver->remove(codec, codec->driver);
-	kfree(codec);
-}
-
-EXPORT_SYMBOL(ac97_release_codec);
-
-/**
- *	ac97_probe_codec - Initialize and setup AC97-compatible codec
- *	@codec: (in/out) Kernel info for a single AC97 codec
- *
- *	Reset the AC97 codec, then initialize the mixer and
- *	the rest of the @codec structure.
- *
- *	The codec_read and codec_write fields of @codec are
- *	required to be setup and working when this function
- *	is called.  All other fields are set by this function.
- *
- *	codec_wait field of @codec can optionally be provided
- *	when calling this function.  If codec_wait is not %NULL,
- *	this function will call codec_wait any time it is
- *	necessary to wait for the audio chip to reach the
- *	codec-ready state.  If codec_wait is %NULL, then
- *	the default behavior is to call schedule_timeout.
- *	Currently codec_wait is used to wait for AC97 codec
- *	reset to complete. 
- *
- *     Some codecs will power down when a register reset is
- *     performed. We now check for such codecs.
- *
- *	Returns 1 (true) on success, or 0 (false) on failure.
- */
- 
-int ac97_probe_codec(struct ac97_codec *codec)
-{
-	u16 id1, id2;
-	u16 audio;
-	int i;
-	char cidbuf[CODEC_ID_BUFSZ];
-	u16 f;
-	struct list_head *l;
-	struct ac97_driver *d;
-	
-	/* wait for codec-ready state */
-	if (codec->codec_wait)
-		codec->codec_wait(codec);
-	else
-		udelay(10);
-
-	/* will the codec power down if register reset ? */
-	id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
-	id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
-	codec->name = NULL;
-	codec->codec_ops = &null_ops;
-	for (i = 0; i < ARRAY_SIZE(ac97_codec_ids); i++) {
-		if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
-			codec->type = ac97_codec_ids[i].id;
-			codec->name = ac97_codec_ids[i].name;
-			codec->codec_ops = ac97_codec_ids[i].ops;
-			codec->flags = ac97_codec_ids[i].flags;
-			break;
-		}
-	}
-
-	codec->model = (id1 << 16) | id2;
-	if ((codec->flags & AC97_DEFAULT_POWER_OFF) == 0) {
-		/* reset codec and wait for the ready bit before we continue */
-		codec->codec_write(codec, AC97_RESET, 0L);
-		if (codec->codec_wait)
-			codec->codec_wait(codec);
-		else
-			udelay(10);
-	}
-
-	/* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should
-	 * be read zero.
-	 *
-	 * FIXME: is the following comment outdated?  -jgarzik
-	 * Probing of AC97 in this way is not reliable, it is not even SAFE !!
-	 */
-	if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) {
-		printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n",
-		       (codec->id & 0x2) ? (codec->id&1 ? "4th" : "Tertiary")
-		       : (codec->id&1 ? "Secondary":  "Primary"));
-		return 0;
-	}
-	
-	/* probe for Modem Codec */
-	codec->modem = ac97_check_modem(codec);
-
-	/* enable SPDIF */
-	f = codec->codec_read(codec, AC97_EXTENDED_STATUS);
-	if((codec->codec_ops == &null_ops) && (f & 4))
-		codec->codec_ops = &default_digital_ops;
-	
-	/* A device which thinks its a modem but isn't */
-	if(codec->flags & AC97_DELUDED_MODEM)
-		codec->modem = 0;
-		
-	if (codec->name == NULL)
-		codec->name = "Unknown";
-	printk(KERN_INFO "ac97_codec: AC97 %s codec, id: %s (%s)\n", 
-		codec->modem ? "Modem" : (audio ? "Audio" : ""),
-	       codec_id(id1, id2, cidbuf), codec->name);
-
-	if(!ac97_init_mixer(codec))
-		return 0;
-		
-	/* 
-	 *	Attach last so the caller can override the mixer
-	 *	callbacks.
-	 */
-	 
-	mutex_lock(&codec_mutex);
-	list_add(&codec->list, &codecs);
-
-	list_for_each(l, &codec_drivers) {
-		d = list_entry(l, struct ac97_driver, list);
-		if ((codec->model ^ d->codec_id) & d->codec_mask)
-			continue;
-		if(d->probe(codec, d) == 0)
-		{
-			codec->driver = d;
-			break;
-		}
-	}
-
-	mutex_unlock(&codec_mutex);
-	return 1;
-}
-
-static int ac97_init_mixer(struct ac97_codec *codec)
-{
-	u16 cap;
-	int i;
-
-	cap = codec->codec_read(codec, AC97_RESET);
-
-	/* mixer masks */
-	codec->supported_mixers = AC97_SUPPORTED_MASK;
-	codec->stereo_mixers = AC97_STEREO_MASK;
-	codec->record_sources = AC97_RECORD_MASK;
-	if (!(cap & 0x04))
-		codec->supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE);
-	if (!(cap & 0x10))
-		codec->supported_mixers &= ~SOUND_MASK_ALTPCM;
-
-
-	/* detect bit resolution */
-	codec->codec_write(codec, AC97_MASTER_VOL_STEREO, 0x2020);
-	if(codec->codec_read(codec, AC97_MASTER_VOL_STEREO) == 0x2020)
-		codec->bit_resolution = 6;
-	else
-		codec->bit_resolution = 5;
-
-	/* generic OSS to AC97 wrapper */
-	codec->read_mixer = ac97_read_mixer;
-	codec->write_mixer = ac97_write_mixer;
-	codec->recmask_io = ac97_recmask_io;
-	codec->mixer_ioctl = ac97_mixer_ioctl;
-
-	/* initialize mixer channel volumes */
-	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
-		struct mixer_defaults *md = &mixer_defaults[i];
-		if (md->mixer == -1) 
-			break;
-		if (!supported_mixer(codec, md->mixer)) 
-			continue;
-		ac97_set_mixer(codec, md->mixer, md->value);
-	}
-
-	/* codec specific initialization for 4-6 channel output or secondary codec stuff */
-	if (codec->codec_ops->init != NULL) {
-		codec->codec_ops->init(codec);
-	}
-
-	/*
-	 *	Volume is MUTE only on this device. We have to initialise
-	 *	it but its useless beyond that.
-	 */
-	if(codec->flags & AC97_NO_PCM_VOLUME)
-	{
-		codec->supported_mixers &= ~SOUND_MASK_PCM;
-		printk(KERN_WARNING "AC97 codec does not have proper volume support.\n");
-	}
-	return 1;
-}
-
-#define AC97_SIGMATEL_ANALOG    0x6c	/* Analog Special */
-#define AC97_SIGMATEL_DAC2INVERT 0x6e
-#define AC97_SIGMATEL_BIAS1     0x70
-#define AC97_SIGMATEL_BIAS2     0x72
-#define AC97_SIGMATEL_MULTICHN  0x74	/* Multi-Channel programming */
-#define AC97_SIGMATEL_CIC1      0x76
-#define AC97_SIGMATEL_CIC2      0x78
-
-
-static int sigmatel_9708_init(struct ac97_codec * codec)
-{
-	u16 codec72, codec6c;
-
-	codec72 = codec->codec_read(codec, AC97_SIGMATEL_BIAS2) & 0x8000;
-	codec6c = codec->codec_read(codec, AC97_SIGMATEL_ANALOG);
-
-	if ((codec72==0) && (codec6c==0)) {
-		codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
-		codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1000);
-		codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba);
-		codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0007);
-	} else if ((codec72==0x8000) && (codec6c==0)) {
-		codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
-		codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1001);
-		codec->codec_write(codec, AC97_SIGMATEL_DAC2INVERT, 0x0008);
-	} else if ((codec72==0x8000) && (codec6c==0x0080)) {
-		/* nothing */
-	}
-	codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000);
-	return 0;
-}
-
-
-static int sigmatel_9721_init(struct ac97_codec * codec)
-{
-	/* Only set up secondary codec */
-	if (codec->id == 0)
-		return 0;
-
-	codec->codec_write(codec, AC97_SURROUND_MASTER, 0L);
-
-	/* initialize SigmaTel STAC9721/23 as secondary codec, decoding AC link
-	   sloc 3,4 = 0x01, slot 7,8 = 0x00, */
-	codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x00);
-
-	/* we don't have the crystal when we are on an AMR card, so use
-	   BIT_CLK as our clock source. Write the magic word ABBA and read
-	   back to enable register 0x78 */
-	codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
-	codec->codec_read(codec, AC97_SIGMATEL_CIC1);
-
-	/* sync all the clocks*/
-	codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x3802);
-
-	return 0;
-}
-
-
-static int sigmatel_9744_init(struct ac97_codec * codec)
-{
-	// patch for SigmaTel
-	codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
-	codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x0000); // is this correct? --jk
-	codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba);
-	codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0002);
-	codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000);
-	return 0;
-}
-
-static int cmedia_init(struct ac97_codec *codec)
-{
-	/* Initialise the CMedia 9739 */
-	/*
-		We could set various options here
-		Register 0x20 bit 0x100 sets mic as center bass
-		Also do multi_channel_ctrl &=~0x3000 |=0x1000
-		
-		For now we set up the GPIO and PC beep 
-	*/
-	
-	u16 v;
-	
-	/* MIC */
-	codec->codec_write(codec, 0x64, 0x3000);
-	v = codec->codec_read(codec, 0x64);
-	v &= ~0x8000;
-	codec->codec_write(codec, 0x64, v);
-	codec->codec_write(codec, 0x70, 0x0100);
-	codec->codec_write(codec, 0x72, 0x0020);
-	return 0;
-}
-	
-#define AC97_WM97XX_FMIXER_VOL 0x72
-#define AC97_WM97XX_RMIXER_VOL 0x74
-#define AC97_WM97XX_TEST 0x5a
-#define AC97_WM9704_RPCM_VOL 0x70
-#define AC97_WM9711_OUT3VOL 0x16
-
-static int wolfson_init03(struct ac97_codec * codec)
-{
-	/* this is known to work for the ViewSonic ViewPad 1000 */
-	codec->codec_write(codec, AC97_WM97XX_FMIXER_VOL, 0x0808);
-	codec->codec_write(codec, AC97_GENERAL_PURPOSE, 0x8000);
-	return 0;
-}
-
-static int wolfson_init04(struct ac97_codec * codec)
-{
-	codec->codec_write(codec, AC97_WM97XX_FMIXER_VOL, 0x0808);
-	codec->codec_write(codec, AC97_WM97XX_RMIXER_VOL, 0x0808);
-
-	// patch for DVD noise
-	codec->codec_write(codec, AC97_WM97XX_TEST, 0x0200);
-
-	// init vol as PCM vol
-	codec->codec_write(codec, AC97_WM9704_RPCM_VOL,
-		codec->codec_read(codec, AC97_PCMOUT_VOL));
-
-	/* set rear surround volume */
-	codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000);
-	return 0;
-}
-
-/* WM9705, WM9710 */
-static int wolfson_init05(struct ac97_codec * codec)
-{
-	/* set front mixer volume */
-	codec->codec_write(codec, AC97_WM97XX_FMIXER_VOL, 0x0808);
-	return 0;
-}
-
-/* WM9711, WM9712 */
-static int wolfson_init11(struct ac97_codec * codec)
-{
-	/* stop pop's during suspend/resume */
-	codec->codec_write(codec, AC97_WM97XX_TEST,
-		codec->codec_read(codec, AC97_WM97XX_TEST) & 0xffbf);
-
-	/* set out3 volume */
-	codec->codec_write(codec, AC97_WM9711_OUT3VOL, 0x0808);
-	return 0;
-}
-
-/* WM9713 */
-static int wolfson_init13(struct ac97_codec * codec)
-{
-	codec->codec_write(codec, AC97_RECORD_GAIN, 0x00a0);
-	codec->codec_write(codec, AC97_POWER_CONTROL, 0x0000);
-	codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0xDA00);
-	codec->codec_write(codec, AC97_EXTEND_MODEM_STAT, 0x3810);
-	codec->codec_write(codec, AC97_PHONE_VOL, 0x0808);
-	codec->codec_write(codec, AC97_PCBEEP_VOL, 0x0808);
-
-	return 0;
-}
-
-static int tritech_init(struct ac97_codec * codec)
-{
-	codec->codec_write(codec, 0x26, 0x0300);
-	codec->codec_write(codec, 0x26, 0x0000);
-	codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000);
-	codec->codec_write(codec, AC97_RESERVED_3A, 0x0000);
-	return 0;
-}
-
-
-/* copied from drivers/sound/maestro.c */
-static int tritech_maestro_init(struct ac97_codec * codec)
-{
-	/* no idea what this does */
-	codec->codec_write(codec, 0x2A, 0x0001);
-	codec->codec_write(codec, 0x2C, 0x0000);
-	codec->codec_write(codec, 0x2C, 0XFFFF);
-	return 0;
-}
-
-
-
-/* 
- *	Presario700 workaround 
- * 	for Jack Sense/SPDIF Register mis-setting causing
- *	no audible output
- *	by Santiago Nullo 04/05/2002
- */
-
-#define AC97_AD1886_JACK_SENSE 0x72
-
-static int ad1886_init(struct ac97_codec * codec)
-{
-	/* from AD1886 Specs */
-	codec->codec_write(codec, AC97_AD1886_JACK_SENSE, 0x0010);
-	return 0;
-}
-
-
-
-
-/*
- *	This is basically standard AC97. It should work as a default for
- *	almost all modern codecs. Note that some cards wire EAPD *backwards*
- *	That side of it is up to the card driver not us to cope with.
- *
- */
-
-static int eapd_control(struct ac97_codec * codec, int on)
-{
-	if(on)
-		codec->codec_write(codec, AC97_POWER_CONTROL,
-			codec->codec_read(codec, AC97_POWER_CONTROL)|0x8000);
-	else
-		codec->codec_write(codec, AC97_POWER_CONTROL,
-			codec->codec_read(codec, AC97_POWER_CONTROL)&~0x8000);
-	return 0;
-}
-
-static int generic_digital_control(struct ac97_codec *codec, int slots, int rate, int mode)
-{
-	u16 reg;
-	
-	reg = codec->codec_read(codec, AC97_SPDIF_CONTROL);
-	
-	switch(rate)
-	{
-		/* Off by default */
-		default:
-		case 0:
-			reg = codec->codec_read(codec, AC97_EXTENDED_STATUS);
-			codec->codec_write(codec, AC97_EXTENDED_STATUS, (reg & ~AC97_EA_SPDIF));
-			if(rate == 0)
-				return 0;
-			return -EINVAL;
-		case 1:
-			reg = (reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_48K;
-			break;
-		case 2:
-			reg = (reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_44K;
-			break;
-		case 3:
-			reg = (reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_32K;
-			break;
-	}
-	
-	reg &= ~AC97_SC_CC_MASK;
-	reg |= (mode & AUDIO_CCMASK) << 6;
-	
-	if(mode & AUDIO_DIGITAL)
-		reg |= 2;
-	if(mode & AUDIO_PRO)
-		reg |= 1;
-	if(mode & AUDIO_DRS)
-		reg |= 0x4000;
-
-	codec->codec_write(codec, AC97_SPDIF_CONTROL, reg);
-
-	reg = codec->codec_read(codec, AC97_EXTENDED_STATUS);
-	reg &= (AC97_EA_SLOT_MASK);
-	reg |= AC97_EA_VRA | AC97_EA_SPDIF | slots;
-	codec->codec_write(codec, AC97_EXTENDED_STATUS, reg);
-	
-	reg = codec->codec_read(codec, AC97_EXTENDED_STATUS);
-	if(!(reg & 0x0400))
-	{
-		codec->codec_write(codec, AC97_EXTENDED_STATUS, reg & ~ AC97_EA_SPDIF);
-		return -EINVAL;
-	}
-	return 0;
-}
-
-/*
- *	Crystal digital audio control (CS4299)
- */
- 
-static int crystal_digital_control(struct ac97_codec *codec, int slots, int rate, int mode)
-{
-	u16 cv;
-
-	if(mode & AUDIO_DIGITAL)
-		return -EINVAL;
-		
-	switch(rate)
-	{
-		case 0: cv = 0x0; break;	/* SPEN off */
-		case 48000: cv = 0x8004; break;	/* 48KHz digital */
-		case 44100: cv = 0x8104; break;	/* 44.1KHz digital */
-		case 32768: 			/* 32Khz */
-		default:
-			return -EINVAL;
-	}
-	codec->codec_write(codec, 0x68, cv);
-	return 0;
-}
-
-/*
- *	CMedia digital audio control
- *	Needs more work.
- */
- 
-static int cmedia_digital_control(struct ac97_codec *codec, int slots, int rate, int mode)
-{
-	u16 cv;
-
-	if(mode & AUDIO_DIGITAL)
-		return -EINVAL;
-		
-	switch(rate)
-	{
-		case 0:		cv = 0x0001; break;	/* SPEN off */
-		case 48000:	cv = 0x0009; break;	/* 48KHz digital */
-		default:
-			return -EINVAL;
-	}
-	codec->codec_write(codec, 0x2A, 0x05c4);
-	codec->codec_write(codec, 0x6C, cv);
-	
-	/* Switch on mix to surround */
-	cv = codec->codec_read(codec, 0x64);
-	cv &= ~0x0200;
-	if(mode)
-		cv |= 0x0200;
-	codec->codec_write(codec, 0x64, cv);
-	return 0;
-}
-
-
-/* copied from drivers/sound/maestro.c */
-#if 0  /* there has been 1 person on the planet with a pt101 that we
-        know of.  If they care, they can put this back in :) */
-static int pt101_init(struct ac97_codec * codec)
-{
-	printk(KERN_INFO "ac97_codec: PT101 Codec detected, initializing but _not_ installing mixer device.\n");
-	/* who knows.. */
-	codec->codec_write(codec, 0x2A, 0x0001);
-	codec->codec_write(codec, 0x2C, 0x0000);
-	codec->codec_write(codec, 0x2C, 0xFFFF);
-	codec->codec_write(codec, 0x10, 0x9F1F);
-	codec->codec_write(codec, 0x12, 0x0808);
-	codec->codec_write(codec, 0x14, 0x9F1F);
-	codec->codec_write(codec, 0x16, 0x9F1F);
-	codec->codec_write(codec, 0x18, 0x0404);
-	codec->codec_write(codec, 0x1A, 0x0000);
-	codec->codec_write(codec, 0x1C, 0x0000);
-	codec->codec_write(codec, 0x02, 0x0404);
-	codec->codec_write(codec, 0x04, 0x0808);
-	codec->codec_write(codec, 0x0C, 0x801F);
-	codec->codec_write(codec, 0x0E, 0x801F);
-	return 0;
-}
-#endif
-	
-
-EXPORT_SYMBOL(ac97_probe_codec);
-
-MODULE_LICENSE("GPL");
-
diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c
deleted file mode 100644
index a8f626d99c5b..000000000000
--- a/sound/oss/au1550_ac97.c
+++ /dev/null
@@ -1,2147 +0,0 @@
-/*
- * au1550_ac97.c  --  Sound driver for Alchemy Au1550 MIPS Internet Edge
- *                    Processor.
- *
- * Copyright 2004 Embedded Edge, LLC
- *	dan@embeddededge.com
- *
- * Mostly copied from the au1000.c driver and some from the
- * PowerMac dbdma driver.
- * We assume the processor can do memory coherent DMA.
- *
- * Ported to 2.6 by Matt Porter <mporter@kernel.crashing.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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#undef DEBUG
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/poll.h>
-#include <linux/bitops.h>
-#include <linux/spinlock.h>
-#include <linux/ac97_codec.h>
-#include <linux/mutex.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/hardirq.h>
-#include <asm/mach-au1x00/au1xxx_psc.h>
-#include <asm/mach-au1x00/au1xxx_dbdma.h>
-#include <asm/mach-au1x00/au1xxx.h>
-
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-
-/* misc stuff */
-#define POLL_COUNT   0x50000
-#define AC97_EXT_DACS (AC97_EXTID_SDAC | AC97_EXTID_CDAC | AC97_EXTID_LDAC)
-
-/* The number of DBDMA ring descriptors to allocate.  No sense making
- * this too large....if you can't keep up with a few you aren't likely
- * to be able to with lots of them, either.
- */
-#define NUM_DBDMA_DESCRIPTORS 4
-
-#define err(format, arg...) printk(KERN_ERR format "\n" , ## arg)
-
-/* Boot options
- * 0 = no VRA, 1 = use VRA if codec supports it
- */
-static DEFINE_MUTEX(au1550_ac97_mutex);
-static int      vra = 1;
-module_param(vra, bool, 0);
-MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it");
-
-static struct au1550_state {
-	/* soundcore stuff */
-	int             dev_audio;
-
-	struct ac97_codec *codec;
-	unsigned        codec_base_caps; /* AC'97 reg 00h, "Reset Register" */
-	unsigned        codec_ext_caps;  /* AC'97 reg 28h, "Extended Audio ID" */
-	int             no_vra;		/* do not use VRA */
-
-	spinlock_t      lock;
-	struct mutex open_mutex;
-	struct mutex sem;
-	fmode_t          open_mode;
-	wait_queue_head_t open_wait;
-
-	struct dmabuf {
-		u32		dmanr;
-		unsigned        sample_rate;
-		unsigned	src_factor;
-		unsigned        sample_size;
-		int             num_channels;
-		int		dma_bytes_per_sample;
-		int		user_bytes_per_sample;
-		int		cnt_factor;
-
-		void		*rawbuf;
-		unsigned        buforder;
-		unsigned	numfrag;
-		unsigned        fragshift;
-		void		*nextIn;
-		void		*nextOut;
-		int		count;
-		unsigned        total_bytes;
-		unsigned        error;
-		wait_queue_head_t wait;
-
-		/* redundant, but makes calculations easier */
-		unsigned	fragsize;
-		unsigned	dma_fragsize;
-		unsigned	dmasize;
-		unsigned	dma_qcount;
-
-		/* OSS stuff */
-		unsigned        mapped:1;
-		unsigned        ready:1;
-		unsigned        stopped:1;
-		unsigned        ossfragshift;
-		int             ossmaxfrags;
-		unsigned        subdivision;
-	} dma_dac, dma_adc;
-} au1550_state;
-
-static unsigned
-ld2(unsigned int x)
-{
-	unsigned        r = 0;
-
-	if (x >= 0x10000) {
-		x >>= 16;
-		r += 16;
-	}
-	if (x >= 0x100) {
-		x >>= 8;
-		r += 8;
-	}
-	if (x >= 0x10) {
-		x >>= 4;
-		r += 4;
-	}
-	if (x >= 4) {
-		x >>= 2;
-		r += 2;
-	}
-	if (x >= 2)
-		r++;
-	return r;
-}
-
-static void
-au1550_delay(int msec)
-{
-	if (in_interrupt())
-		return;
-
-	schedule_timeout_uninterruptible(msecs_to_jiffies(msec));
-}
-
-static u16
-rdcodec(struct ac97_codec *codec, u8 addr)
-{
-	struct au1550_state *s = codec->private_data;
-	unsigned long   flags;
-	u32             cmd, val;
-	u16             data;
-	int             i;
-
-	spin_lock_irqsave(&s->lock, flags);
-
-	for (i = 0; i < POLL_COUNT; i++) {
-		val = au_readl(PSC_AC97STAT);
-		au_sync();
-		if (!(val & PSC_AC97STAT_CP))
-			break;
-	}
-	if (i == POLL_COUNT)
-		err("rdcodec: codec cmd pending expired!");
-
-	cmd = (u32)PSC_AC97CDC_INDX(addr);
-	cmd |= PSC_AC97CDC_RD;	/* read command */
-	au_writel(cmd, PSC_AC97CDC);
-	au_sync();
-
-	/* now wait for the data
-	*/
-	for (i = 0; i < POLL_COUNT; i++) {
-		val = au_readl(PSC_AC97STAT);
-		au_sync();
-		if (!(val & PSC_AC97STAT_CP))
-			break;
-	}
-	if (i == POLL_COUNT) {
-		err("rdcodec: read poll expired!");
-		data = 0;
-		goto out;
-	}
-
-	/* wait for command done?
-	*/
-	for (i = 0; i < POLL_COUNT; i++) {
-		val = au_readl(PSC_AC97EVNT);
-		au_sync();
-		if (val & PSC_AC97EVNT_CD)
-			break;
-	}
-	if (i == POLL_COUNT) {
-		err("rdcodec: read cmdwait expired!");
-		data = 0;
-		goto out;
-	}
-
-	data = au_readl(PSC_AC97CDC) & 0xffff;
-	au_sync();
-
-	/* Clear command done event.
-	*/
-	au_writel(PSC_AC97EVNT_CD, PSC_AC97EVNT);
-	au_sync();
-
- out:
-	spin_unlock_irqrestore(&s->lock, flags);
-
-	return data;
-}
-
-
-static void
-wrcodec(struct ac97_codec *codec, u8 addr, u16 data)
-{
-	struct au1550_state *s = codec->private_data;
-	unsigned long   flags;
-	u32             cmd, val;
-	int             i;
-
-	spin_lock_irqsave(&s->lock, flags);
-
-	for (i = 0; i < POLL_COUNT; i++) {
-		val = au_readl(PSC_AC97STAT);
-		au_sync();
-		if (!(val & PSC_AC97STAT_CP))
-			break;
-	}
-	if (i == POLL_COUNT)
-		err("wrcodec: codec cmd pending expired!");
-
-	cmd = (u32)PSC_AC97CDC_INDX(addr);
-	cmd |= (u32)data;
-	au_writel(cmd, PSC_AC97CDC);
-	au_sync();
-
-	for (i = 0; i < POLL_COUNT; i++) {
-		val = au_readl(PSC_AC97STAT);
-		au_sync();
-		if (!(val & PSC_AC97STAT_CP))
-			break;
-	}
-	if (i == POLL_COUNT)
-		err("wrcodec: codec cmd pending expired!");
-
-	for (i = 0; i < POLL_COUNT; i++) {
-		val = au_readl(PSC_AC97EVNT);
-		au_sync();
-		if (val & PSC_AC97EVNT_CD)
-			break;
-	}
-	if (i == POLL_COUNT)
-		err("wrcodec: read cmdwait expired!");
-
-	/* Clear command done event.
-	*/
-	au_writel(PSC_AC97EVNT_CD, PSC_AC97EVNT);
-	au_sync();
-
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void
-waitcodec(struct ac97_codec *codec)
-{
-	u16	temp;
-	u32	val;
-	int	i;
-
-	/* codec_wait is used to wait for a ready state after
-	 * an AC97C_RESET.
-	 */
-	au1550_delay(10);
-
-	/* first poll the CODEC_READY tag bit
-	*/
-	for (i = 0; i < POLL_COUNT; i++) {
-		val = au_readl(PSC_AC97STAT);
-		au_sync();
-		if (val & PSC_AC97STAT_CR)
-			break;
-	}
-	if (i == POLL_COUNT) {
-		err("waitcodec: CODEC_READY poll expired!");
-		return;
-	}
-
-	/* get AC'97 powerdown control/status register
-	*/
-	temp = rdcodec(codec, AC97_POWER_CONTROL);
-
-	/* If anything is powered down, power'em up
-	*/
-	if (temp & 0x7f00) {
-		/* Power on
-		*/
-		wrcodec(codec, AC97_POWER_CONTROL, 0);
-		au1550_delay(100);
-
-		/* Reread
-		*/
-		temp = rdcodec(codec, AC97_POWER_CONTROL);
-	}
-
-	/* Check if Codec REF,ANL,DAC,ADC ready
-	*/
-	if ((temp & 0x7f0f) != 0x000f)
-		err("codec reg 26 status (0x%x) not ready!!", temp);
-}
-
-/* stop the ADC before calling */
-static void
-set_adc_rate(struct au1550_state *s, unsigned rate)
-{
-	struct dmabuf  *adc = &s->dma_adc;
-	struct dmabuf  *dac = &s->dma_dac;
-	unsigned        adc_rate, dac_rate;
-	u16             ac97_extstat;
-
-	if (s->no_vra) {
-		/* calc SRC factor
-		*/
-		adc->src_factor = ((96000 / rate) + 1) >> 1;
-		adc->sample_rate = 48000 / adc->src_factor;
-		return;
-	}
-
-	adc->src_factor = 1;
-
-	ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS);
-
-	rate = rate > 48000 ? 48000 : rate;
-
-	/* enable VRA
-	*/
-	wrcodec(s->codec, AC97_EXTENDED_STATUS,
-		ac97_extstat | AC97_EXTSTAT_VRA);
-
-	/* now write the sample rate
-	*/
-	wrcodec(s->codec, AC97_PCM_LR_ADC_RATE, (u16) rate);
-
-	/* read it back for actual supported rate
-	*/
-	adc_rate = rdcodec(s->codec, AC97_PCM_LR_ADC_RATE);
-
-	pr_debug("set_adc_rate: set to %d Hz\n", adc_rate);
-
-	/* some codec's don't allow unequal DAC and ADC rates, in which case
-	 * writing one rate reg actually changes both.
-	 */
-	dac_rate = rdcodec(s->codec, AC97_PCM_FRONT_DAC_RATE);
-	if (dac->num_channels > 2)
-		wrcodec(s->codec, AC97_PCM_SURR_DAC_RATE, dac_rate);
-	if (dac->num_channels > 4)
-		wrcodec(s->codec, AC97_PCM_LFE_DAC_RATE, dac_rate);
-
-	adc->sample_rate = adc_rate;
-	dac->sample_rate = dac_rate;
-}
-
-/* stop the DAC before calling */
-static void
-set_dac_rate(struct au1550_state *s, unsigned rate)
-{
-	struct dmabuf  *dac = &s->dma_dac;
-	struct dmabuf  *adc = &s->dma_adc;
-	unsigned        adc_rate, dac_rate;
-	u16             ac97_extstat;
-
-	if (s->no_vra) {
-		/* calc SRC factor
-		*/
-		dac->src_factor = ((96000 / rate) + 1) >> 1;
-		dac->sample_rate = 48000 / dac->src_factor;
-		return;
-	}
-
-	dac->src_factor = 1;
-
-	ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS);
-
-	rate = rate > 48000 ? 48000 : rate;
-
-	/* enable VRA
-	*/
-	wrcodec(s->codec, AC97_EXTENDED_STATUS,
-		ac97_extstat | AC97_EXTSTAT_VRA);
-
-	/* now write the sample rate
-	*/
-	wrcodec(s->codec, AC97_PCM_FRONT_DAC_RATE, (u16) rate);
-
-	/* I don't support different sample rates for multichannel,
-	 * so make these channels the same.
-	 */
-	if (dac->num_channels > 2)
-		wrcodec(s->codec, AC97_PCM_SURR_DAC_RATE, (u16) rate);
-	if (dac->num_channels > 4)
-		wrcodec(s->codec, AC97_PCM_LFE_DAC_RATE, (u16) rate);
-	/* read it back for actual supported rate
-	*/
-	dac_rate = rdcodec(s->codec, AC97_PCM_FRONT_DAC_RATE);
-
-	pr_debug("set_dac_rate: set to %d Hz\n", dac_rate);
-
-	/* some codec's don't allow unequal DAC and ADC rates, in which case
-	 * writing one rate reg actually changes both.
-	 */
-	adc_rate = rdcodec(s->codec, AC97_PCM_LR_ADC_RATE);
-
-	dac->sample_rate = dac_rate;
-	adc->sample_rate = adc_rate;
-}
-
-static void
-stop_dac(struct au1550_state *s)
-{
-	struct dmabuf  *db = &s->dma_dac;
-	u32		stat;
-	unsigned long   flags;
-
-	if (db->stopped)
-		return;
-
-	spin_lock_irqsave(&s->lock, flags);
-
-	au_writel(PSC_AC97PCR_TP, PSC_AC97PCR);
-	au_sync();
-
-	/* Wait for Transmit Busy to show disabled.
-	*/
-	do {
-		stat = au_readl(PSC_AC97STAT);
-		au_sync();
-	} while ((stat & PSC_AC97STAT_TB) != 0);
-
-	au1xxx_dbdma_reset(db->dmanr);
-
-	db->stopped = 1;
-
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void
-stop_adc(struct au1550_state *s)
-{
-	struct dmabuf  *db = &s->dma_adc;
-	unsigned long   flags;
-	u32		stat;
-
-	if (db->stopped)
-		return;
-
-	spin_lock_irqsave(&s->lock, flags);
-
-	au_writel(PSC_AC97PCR_RP, PSC_AC97PCR);
-	au_sync();
-
-	/* Wait for Receive Busy to show disabled.
-	*/
-	do {
-		stat = au_readl(PSC_AC97STAT);
-		au_sync();
-	} while ((stat & PSC_AC97STAT_RB) != 0);
-
-	au1xxx_dbdma_reset(db->dmanr);
-
-	db->stopped = 1;
-
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-
-static void
-set_xmit_slots(int num_channels)
-{
-	u32	ac97_config, stat;
-
-	ac97_config = au_readl(PSC_AC97CFG);
-	au_sync();
-	ac97_config &= ~(PSC_AC97CFG_TXSLOT_MASK | PSC_AC97CFG_DE_ENABLE);
-	au_writel(ac97_config, PSC_AC97CFG);
-	au_sync();
-
-	switch (num_channels) {
-	case 6:		/* stereo with surround and center/LFE,
-			 * slots 3,4,6,7,8,9
-			 */
-		ac97_config |= PSC_AC97CFG_TXSLOT_ENA(6);
-		ac97_config |= PSC_AC97CFG_TXSLOT_ENA(9);
-
-	case 4:		/* stereo with surround, slots 3,4,7,8 */
-		ac97_config |= PSC_AC97CFG_TXSLOT_ENA(7);
-		ac97_config |= PSC_AC97CFG_TXSLOT_ENA(8);
-
-	case 2:		/* stereo, slots 3,4 */
-	case 1:		/* mono */
-		ac97_config |= PSC_AC97CFG_TXSLOT_ENA(3);
-		ac97_config |= PSC_AC97CFG_TXSLOT_ENA(4);
-	}
-
-	au_writel(ac97_config, PSC_AC97CFG);
-	au_sync();
-
-	ac97_config |= PSC_AC97CFG_DE_ENABLE;
-	au_writel(ac97_config, PSC_AC97CFG);
-	au_sync();
-
-	/* Wait for Device ready.
-	*/
-	do {
-		stat = au_readl(PSC_AC97STAT);
-		au_sync();
-	} while ((stat & PSC_AC97STAT_DR) == 0);
-}
-
-static void
-set_recv_slots(int num_channels)
-{
-	u32	ac97_config, stat;
-
-	ac97_config = au_readl(PSC_AC97CFG);
-	au_sync();
-	ac97_config &= ~(PSC_AC97CFG_RXSLOT_MASK | PSC_AC97CFG_DE_ENABLE);
-	au_writel(ac97_config, PSC_AC97CFG);
-	au_sync();
-
-	/* Always enable slots 3 and 4 (stereo). Slot 6 is
-	 * optional Mic ADC, which we don't support yet.
-	 */
-	ac97_config |= PSC_AC97CFG_RXSLOT_ENA(3);
-	ac97_config |= PSC_AC97CFG_RXSLOT_ENA(4);
-
-	au_writel(ac97_config, PSC_AC97CFG);
-	au_sync();
-
-	ac97_config |= PSC_AC97CFG_DE_ENABLE;
-	au_writel(ac97_config, PSC_AC97CFG);
-	au_sync();
-
-	/* Wait for Device ready.
-	*/
-	do {
-		stat = au_readl(PSC_AC97STAT);
-		au_sync();
-	} while ((stat & PSC_AC97STAT_DR) == 0);
-}
-
-/* Hold spinlock for both start_dac() and start_adc() calls */
-static void
-start_dac(struct au1550_state *s)
-{
-	struct dmabuf  *db = &s->dma_dac;
-
-	if (!db->stopped)
-		return;
-
-	set_xmit_slots(db->num_channels);
-	au_writel(PSC_AC97PCR_TC, PSC_AC97PCR);
-	au_sync();
-	au_writel(PSC_AC97PCR_TS, PSC_AC97PCR);
-	au_sync();
-
-	au1xxx_dbdma_start(db->dmanr);
-
-	db->stopped = 0;
-}
-
-static void
-start_adc(struct au1550_state *s)
-{
-	struct dmabuf  *db = &s->dma_adc;
-	int	i;
-
-	if (!db->stopped)
-		return;
-
-	/* Put two buffers on the ring to get things started.
-	*/
-	for (i=0; i<2; i++) {
-		au1xxx_dbdma_put_dest(db->dmanr, virt_to_phys(db->nextIn),
-				db->dma_fragsize, DDMA_FLAGS_IE);
-
-		db->nextIn += db->dma_fragsize;
-		if (db->nextIn >= db->rawbuf + db->dmasize)
-			db->nextIn -= db->dmasize;
-	}
-
-	set_recv_slots(db->num_channels);
-	au1xxx_dbdma_start(db->dmanr);
-	au_writel(PSC_AC97PCR_RC, PSC_AC97PCR);
-	au_sync();
-	au_writel(PSC_AC97PCR_RS, PSC_AC97PCR);
-	au_sync();
-
-	db->stopped = 0;
-}
-
-static int
-prog_dmabuf(struct au1550_state *s, struct dmabuf *db)
-{
-	unsigned user_bytes_per_sec;
-	unsigned        bufs;
-	unsigned        rate = db->sample_rate;
-
-	if (!db->rawbuf) {
-		db->ready = db->mapped = 0;
-		db->buforder = 5;	/* 32 * PAGE_SIZE */
-		db->rawbuf = kmalloc((PAGE_SIZE << db->buforder), GFP_KERNEL);
-		if (!db->rawbuf)
-			return -ENOMEM;
-	}
-
-	db->cnt_factor = 1;
-	if (db->sample_size == 8)
-		db->cnt_factor *= 2;
-	if (db->num_channels == 1)
-		db->cnt_factor *= 2;
-	db->cnt_factor *= db->src_factor;
-
-	db->count = 0;
-	db->dma_qcount = 0;
-	db->nextIn = db->nextOut = db->rawbuf;
-
-	db->user_bytes_per_sample = (db->sample_size>>3) * db->num_channels;
-	db->dma_bytes_per_sample = 2 * ((db->num_channels == 1) ?
-					2 : db->num_channels);
-
-	user_bytes_per_sec = rate * db->user_bytes_per_sample;
-	bufs = PAGE_SIZE << db->buforder;
-	if (db->ossfragshift) {
-		if ((1000 << db->ossfragshift) < user_bytes_per_sec)
-			db->fragshift = ld2(user_bytes_per_sec/1000);
-		else
-			db->fragshift = db->ossfragshift;
-	} else {
-		db->fragshift = ld2(user_bytes_per_sec / 100 /
-				    (db->subdivision ? db->subdivision : 1));
-		if (db->fragshift < 3)
-			db->fragshift = 3;
-	}
-
-	db->fragsize = 1 << db->fragshift;
-	db->dma_fragsize = db->fragsize * db->cnt_factor;
-	db->numfrag = bufs / db->dma_fragsize;
-
-	while (db->numfrag < 4 && db->fragshift > 3) {
-		db->fragshift--;
-		db->fragsize = 1 << db->fragshift;
-		db->dma_fragsize = db->fragsize * db->cnt_factor;
-		db->numfrag = bufs / db->dma_fragsize;
-	}
-
-	if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
-		db->numfrag = db->ossmaxfrags;
-
-	db->dmasize = db->dma_fragsize * db->numfrag;
-	memset(db->rawbuf, 0, bufs);
-
-	pr_debug("prog_dmabuf: rate=%d, samplesize=%d, channels=%d\n",
-	    rate, db->sample_size, db->num_channels);
-	pr_debug("prog_dmabuf: fragsize=%d, cnt_factor=%d, dma_fragsize=%d\n",
-	    db->fragsize, db->cnt_factor, db->dma_fragsize);
-	pr_debug("prog_dmabuf: numfrag=%d, dmasize=%d\n", db->numfrag, db->dmasize);
-
-	db->ready = 1;
-	return 0;
-}
-
-static int
-prog_dmabuf_adc(struct au1550_state *s)
-{
-	stop_adc(s);
-	return prog_dmabuf(s, &s->dma_adc);
-
-}
-
-static int
-prog_dmabuf_dac(struct au1550_state *s)
-{
-	stop_dac(s);
-	return prog_dmabuf(s, &s->dma_dac);
-}
-
-
-static void dac_dma_interrupt(int irq, void *dev_id)
-{
-	struct au1550_state *s = (struct au1550_state *) dev_id;
-	struct dmabuf  *db = &s->dma_dac;
-	u32	ac97c_stat;
-
-	spin_lock(&s->lock);
-
-	ac97c_stat = au_readl(PSC_AC97STAT);
-	if (ac97c_stat & (AC97C_XU | AC97C_XO | AC97C_TE))
-		pr_debug("AC97C status = 0x%08x\n", ac97c_stat);
-	db->dma_qcount--;
-
-	if (db->count >= db->fragsize) {
-		if (au1xxx_dbdma_put_source(db->dmanr,
-				virt_to_phys(db->nextOut), db->fragsize,
-				DDMA_FLAGS_IE) == 0) {
-			err("qcount < 2 and no ring room!");
-		}
-		db->nextOut += db->fragsize;
-		if (db->nextOut >= db->rawbuf + db->dmasize)
-			db->nextOut -= db->dmasize;
-		db->count -= db->fragsize;
-		db->total_bytes += db->dma_fragsize;
-		db->dma_qcount++;
-	}
-
-	/* wake up anybody listening */
-	if (waitqueue_active(&db->wait))
-		wake_up(&db->wait);
-
-	spin_unlock(&s->lock);
-}
-
-
-static void adc_dma_interrupt(int irq, void *dev_id)
-{
-	struct	au1550_state *s = (struct au1550_state *)dev_id;
-	struct	dmabuf  *dp = &s->dma_adc;
-	u32	obytes;
-	char	*obuf;
-
-	spin_lock(&s->lock);
-
-	/* Pull the buffer from the dma queue.
-	*/
-	au1xxx_dbdma_get_dest(dp->dmanr, (void *)(&obuf), &obytes);
-
-	if ((dp->count + obytes) > dp->dmasize) {
-		/* Overrun. Stop ADC and log the error
-		*/
-		spin_unlock(&s->lock);
-		stop_adc(s);
-		dp->error++;
-		err("adc overrun");
-		return;
-	}
-
-	/* Put a new empty buffer on the destination DMA.
-	*/
-	au1xxx_dbdma_put_dest(dp->dmanr, virt_to_phys(dp->nextIn),
-			      dp->dma_fragsize, DDMA_FLAGS_IE);
-
-	dp->nextIn += dp->dma_fragsize;
-	if (dp->nextIn >= dp->rawbuf + dp->dmasize)
-		dp->nextIn -= dp->dmasize;
-
-	dp->count += obytes;
-	dp->total_bytes += obytes;
-
-	/* wake up anybody listening
-	*/
-	if (waitqueue_active(&dp->wait))
-		wake_up(&dp->wait);
-
-	spin_unlock(&s->lock);
-}
-
-static loff_t
-au1550_llseek(struct file *file, loff_t offset, int origin)
-{
-	return -ESPIPE;
-}
-
-
-static int
-au1550_open_mixdev(struct inode *inode, struct file *file)
-{
-	mutex_lock(&au1550_ac97_mutex);
-	file->private_data = &au1550_state;
-	mutex_unlock(&au1550_ac97_mutex);
-	return 0;
-}
-
-static int
-au1550_release_mixdev(struct inode *inode, struct file *file)
-{
-	return 0;
-}
-
-static int
-mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd,
-                        unsigned long arg)
-{
-	return codec->mixer_ioctl(codec, cmd, arg);
-}
-
-static long
-au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct au1550_state *s = file->private_data;
-	struct ac97_codec *codec = s->codec;
-	int ret;
-
-	mutex_lock(&au1550_ac97_mutex);
-	ret = mixdev_ioctl(codec, cmd, arg);
-	mutex_unlock(&au1550_ac97_mutex);
-
-	return ret;
-}
-
-static /*const */ struct file_operations au1550_mixer_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= au1550_llseek,
-	.unlocked_ioctl	= au1550_ioctl_mixdev,
-	.open		= au1550_open_mixdev,
-	.release	= au1550_release_mixdev,
-};
-
-static int
-drain_dac(struct au1550_state *s, int nonblock)
-{
-	unsigned long   flags;
-	int             count, tmo;
-
-	if (s->dma_dac.mapped || !s->dma_dac.ready || s->dma_dac.stopped)
-		return 0;
-
-	for (;;) {
-		spin_lock_irqsave(&s->lock, flags);
-		count = s->dma_dac.count;
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count <= s->dma_dac.fragsize)
-			break;
-		if (signal_pending(current))
-			break;
-		if (nonblock)
-			return -EBUSY;
-		tmo = 1000 * count / (s->no_vra ?
-				      48000 : s->dma_dac.sample_rate);
-		tmo /= s->dma_dac.dma_bytes_per_sample;
-		au1550_delay(tmo);
-	}
-	if (signal_pending(current))
-		return -ERESTARTSYS;
-	return 0;
-}
-
-static inline u8 S16_TO_U8(s16 ch)
-{
-	return (u8) (ch >> 8) + 0x80;
-}
-static inline s16 U8_TO_S16(u8 ch)
-{
-	return (s16) (ch - 0x80) << 8;
-}
-
-/*
- * Translates user samples to dma buffer suitable for AC'97 DAC data:
- *     If mono, copy left channel to right channel in dma buffer.
- *     If 8 bit samples, cvt to 16-bit before writing to dma buffer.
- *     If interpolating (no VRA), duplicate every audio frame src_factor times.
- */
-static int
-translate_from_user(struct dmabuf *db, char* dmabuf, char* userbuf,
-							       int dmacount)
-{
-	int             sample, i;
-	int             interp_bytes_per_sample;
-	int             num_samples;
-	int             mono = (db->num_channels == 1);
-	char            usersample[12];
-	s16             ch, dmasample[6];
-
-	if (db->sample_size == 16 && !mono && db->src_factor == 1) {
-		/* no translation necessary, just copy
-		*/
-		if (copy_from_user(dmabuf, userbuf, dmacount))
-			return -EFAULT;
-		return dmacount;
-	}
-
-	interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor;
-	num_samples = dmacount / interp_bytes_per_sample;
-
-	for (sample = 0; sample < num_samples; sample++) {
-		if (copy_from_user(usersample, userbuf,
-				   db->user_bytes_per_sample)) {
-			return -EFAULT;
-		}
-
-		for (i = 0; i < db->num_channels; i++) {
-			if (db->sample_size == 8)
-				ch = U8_TO_S16(usersample[i]);
-			else
-				ch = *((s16 *) (&usersample[i * 2]));
-			dmasample[i] = ch;
-			if (mono)
-				dmasample[i + 1] = ch;	/* right channel */
-		}
-
-		/* duplicate every audio frame src_factor times
-		*/
-		for (i = 0; i < db->src_factor; i++)
-			memcpy(dmabuf, dmasample, db->dma_bytes_per_sample);
-
-		userbuf += db->user_bytes_per_sample;
-		dmabuf += interp_bytes_per_sample;
-	}
-
-	return num_samples * interp_bytes_per_sample;
-}
-
-/*
- * Translates AC'97 ADC samples to user buffer:
- *     If mono, send only left channel to user buffer.
- *     If 8 bit samples, cvt from 16 to 8 bit before writing to user buffer.
- *     If decimating (no VRA), skip over src_factor audio frames.
- */
-static int
-translate_to_user(struct dmabuf *db, char* userbuf, char* dmabuf,
-							     int dmacount)
-{
-	int             sample, i;
-	int             interp_bytes_per_sample;
-	int             num_samples;
-	int             mono = (db->num_channels == 1);
-	char            usersample[12];
-
-	if (db->sample_size == 16 && !mono && db->src_factor == 1) {
-		/* no translation necessary, just copy
-		*/
-		if (copy_to_user(userbuf, dmabuf, dmacount))
-			return -EFAULT;
-		return dmacount;
-	}
-
-	interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor;
-	num_samples = dmacount / interp_bytes_per_sample;
-
-	for (sample = 0; sample < num_samples; sample++) {
-		for (i = 0; i < db->num_channels; i++) {
-			if (db->sample_size == 8)
-				usersample[i] =
-					S16_TO_U8(*((s16 *) (&dmabuf[i * 2])));
-			else
-				*((s16 *) (&usersample[i * 2])) =
-					*((s16 *) (&dmabuf[i * 2]));
-		}
-
-		if (copy_to_user(userbuf, usersample,
-				 db->user_bytes_per_sample)) {
-			return -EFAULT;
-		}
-
-		userbuf += db->user_bytes_per_sample;
-		dmabuf += interp_bytes_per_sample;
-	}
-
-	return num_samples * interp_bytes_per_sample;
-}
-
-/*
- * Copy audio data to/from user buffer from/to dma buffer, taking care
- * that we wrap when reading/writing the dma buffer. Returns actual byte
- * count written to or read from the dma buffer.
- */
-static int
-copy_dmabuf_user(struct dmabuf *db, char* userbuf, int count, int to_user)
-{
-	char           *bufptr = to_user ? db->nextOut : db->nextIn;
-	char           *bufend = db->rawbuf + db->dmasize;
-	int             cnt, ret;
-
-	if (bufptr + count > bufend) {
-		int             partial = (int) (bufend - bufptr);
-		if (to_user) {
-			if ((cnt = translate_to_user(db, userbuf,
-						     bufptr, partial)) < 0)
-				return cnt;
-			ret = cnt;
-			if ((cnt = translate_to_user(db, userbuf + partial,
-						     db->rawbuf,
-						     count - partial)) < 0)
-				return cnt;
-			ret += cnt;
-		} else {
-			if ((cnt = translate_from_user(db, bufptr, userbuf,
-						       partial)) < 0)
-				return cnt;
-			ret = cnt;
-			if ((cnt = translate_from_user(db, db->rawbuf,
-						       userbuf + partial,
-						       count - partial)) < 0)
-				return cnt;
-			ret += cnt;
-		}
-	} else {
-		if (to_user)
-			ret = translate_to_user(db, userbuf, bufptr, count);
-		else
-			ret = translate_from_user(db, bufptr, userbuf, count);
-	}
-
-	return ret;
-}
-
-
-static ssize_t
-au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
-{
-	struct au1550_state *s = file->private_data;
-	struct dmabuf  *db = &s->dma_adc;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t         ret;
-	unsigned long   flags;
-	int             cnt, usercnt, avail;
-
-	if (db->mapped)
-		return -ENXIO;
-	if (!access_ok(VERIFY_WRITE, buffer, count))
-		return -EFAULT;
-	ret = 0;
-
-	count *= db->cnt_factor;
-
-	mutex_lock(&s->sem);
-	add_wait_queue(&db->wait, &wait);
-
-	while (count > 0) {
-		/* wait for samples in ADC dma buffer
-		*/
-		do {
-			spin_lock_irqsave(&s->lock, flags);
-			if (db->stopped)
-				start_adc(s);
-			avail = db->count;
-			if (avail <= 0)
-				__set_current_state(TASK_INTERRUPTIBLE);
-			spin_unlock_irqrestore(&s->lock, flags);
-			if (avail <= 0) {
-				if (file->f_flags & O_NONBLOCK) {
-					if (!ret)
-						ret = -EAGAIN;
-					goto out;
-				}
-				mutex_unlock(&s->sem);
-				schedule();
-				if (signal_pending(current)) {
-					if (!ret)
-						ret = -ERESTARTSYS;
-					goto out2;
-				}
-				mutex_lock(&s->sem);
-			}
-		} while (avail <= 0);
-
-		/* copy from nextOut to user
-		*/
-		if ((cnt = copy_dmabuf_user(db, buffer,
-					    count > avail ?
-					    avail : count, 1)) < 0) {
-			if (!ret)
-				ret = -EFAULT;
-			goto out;
-		}
-
-		spin_lock_irqsave(&s->lock, flags);
-		db->count -= cnt;
-		db->nextOut += cnt;
-		if (db->nextOut >= db->rawbuf + db->dmasize)
-			db->nextOut -= db->dmasize;
-		spin_unlock_irqrestore(&s->lock, flags);
-
-		count -= cnt;
-		usercnt = cnt / db->cnt_factor;
-		buffer += usercnt;
-		ret += usercnt;
-	}			/* while (count > 0) */
-
-out:
-	mutex_unlock(&s->sem);
-out2:
-	remove_wait_queue(&db->wait, &wait);
-	set_current_state(TASK_RUNNING);
-	return ret;
-}
-
-static ssize_t
-au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
-{
-	struct au1550_state *s = file->private_data;
-	struct dmabuf  *db = &s->dma_dac;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t         ret = 0;
-	unsigned long   flags;
-	int             cnt, usercnt, avail;
-
-	pr_debug("write: count=%d\n", count);
-
-	if (db->mapped)
-		return -ENXIO;
-	if (!access_ok(VERIFY_READ, buffer, count))
-		return -EFAULT;
-
-	count *= db->cnt_factor;
-
-	mutex_lock(&s->sem);
-	add_wait_queue(&db->wait, &wait);
-
-	while (count > 0) {
-		/* wait for space in playback buffer
-		*/
-		do {
-			spin_lock_irqsave(&s->lock, flags);
-			avail = (int) db->dmasize - db->count;
-			if (avail <= 0)
-				__set_current_state(TASK_INTERRUPTIBLE);
-			spin_unlock_irqrestore(&s->lock, flags);
-			if (avail <= 0) {
-				if (file->f_flags & O_NONBLOCK) {
-					if (!ret)
-						ret = -EAGAIN;
-					goto out;
-				}
-				mutex_unlock(&s->sem);
-				schedule();
-				if (signal_pending(current)) {
-					if (!ret)
-						ret = -ERESTARTSYS;
-					goto out2;
-				}
-				mutex_lock(&s->sem);
-			}
-		} while (avail <= 0);
-
-		/* copy from user to nextIn
-		*/
-		if ((cnt = copy_dmabuf_user(db, (char *) buffer,
-					    count > avail ?
-					    avail : count, 0)) < 0) {
-			if (!ret)
-				ret = -EFAULT;
-			goto out;
-		}
-
-		spin_lock_irqsave(&s->lock, flags);
-		db->count += cnt;
-		db->nextIn += cnt;
-		if (db->nextIn >= db->rawbuf + db->dmasize)
-			db->nextIn -= db->dmasize;
-
-		/* If the data is available, we want to keep two buffers
-		 * on the dma queue.  If the queue count reaches zero,
-		 * we know the dma has stopped.
-		 */
-		while ((db->dma_qcount < 2) && (db->count >= db->fragsize)) {
-			if (au1xxx_dbdma_put_source(db->dmanr,
-				virt_to_phys(db->nextOut), db->fragsize,
-				DDMA_FLAGS_IE) == 0) {
-				err("qcount < 2 and no ring room!");
-			}
-			db->nextOut += db->fragsize;
-			if (db->nextOut >= db->rawbuf + db->dmasize)
-				db->nextOut -= db->dmasize;
-			db->total_bytes += db->dma_fragsize;
-			if (db->dma_qcount == 0)
-				start_dac(s);
-			db->dma_qcount++;
-		}
-		spin_unlock_irqrestore(&s->lock, flags);
-
-		count -= cnt;
-		usercnt = cnt / db->cnt_factor;
-		buffer += usercnt;
-		ret += usercnt;
-	}			/* while (count > 0) */
-
-out:
-	mutex_unlock(&s->sem);
-out2:
-	remove_wait_queue(&db->wait, &wait);
-	set_current_state(TASK_RUNNING);
-	return ret;
-}
-
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int
-au1550_poll(struct file *file, struct poll_table_struct *wait)
-{
-	struct au1550_state *s = file->private_data;
-	unsigned long   flags;
-	unsigned int    mask = 0;
-
-	if (file->f_mode & FMODE_WRITE) {
-		if (!s->dma_dac.ready)
-			return 0;
-		poll_wait(file, &s->dma_dac.wait, wait);
-	}
-	if (file->f_mode & FMODE_READ) {
-		if (!s->dma_adc.ready)
-			return 0;
-		poll_wait(file, &s->dma_adc.wait, wait);
-	}
-
-	spin_lock_irqsave(&s->lock, flags);
-
-	if (file->f_mode & FMODE_READ) {
-		if (s->dma_adc.count >= (signed)s->dma_adc.dma_fragsize)
-			mask |= POLLIN | POLLRDNORM;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		if (s->dma_dac.mapped) {
-			if (s->dma_dac.count >=
-			    (signed)s->dma_dac.dma_fragsize)
-				mask |= POLLOUT | POLLWRNORM;
-		} else {
-			if ((signed) s->dma_dac.dmasize >=
-			    s->dma_dac.count + (signed)s->dma_dac.dma_fragsize)
-				mask |= POLLOUT | POLLWRNORM;
-		}
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	return mask;
-}
-
-static int
-au1550_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct au1550_state *s = file->private_data;
-	struct dmabuf  *db;
-	unsigned long   size;
-	int ret = 0;
-
-	mutex_lock(&au1550_ac97_mutex);
-	mutex_lock(&s->sem);
-	if (vma->vm_flags & VM_WRITE)
-		db = &s->dma_dac;
-	else if (vma->vm_flags & VM_READ)
-		db = &s->dma_adc;
-	else {
-		ret = -EINVAL;
-		goto out;
-	}
-	if (vma->vm_pgoff != 0) {
-		ret = -EINVAL;
-		goto out;
-	}
-	size = vma->vm_end - vma->vm_start;
-	if (size > (PAGE_SIZE << db->buforder)) {
-		ret = -EINVAL;
-		goto out;
-	}
-	if (remap_pfn_range(vma, vma->vm_start, page_to_pfn(virt_to_page(db->rawbuf)),
-			     size, vma->vm_page_prot)) {
-		ret = -EAGAIN;
-		goto out;
-	}
-	vma->vm_flags &= ~VM_IO;
-	db->mapped = 1;
-out:
-	mutex_unlock(&s->sem);
-	mutex_unlock(&au1550_ac97_mutex);
-	return ret;
-}
-
-#ifdef DEBUG
-static struct ioctl_str_t {
-	unsigned int    cmd;
-	const char     *str;
-} ioctl_str[] = {
-	{SNDCTL_DSP_RESET, "SNDCTL_DSP_RESET"},
-	{SNDCTL_DSP_SYNC, "SNDCTL_DSP_SYNC"},
-	{SNDCTL_DSP_SPEED, "SNDCTL_DSP_SPEED"},
-	{SNDCTL_DSP_STEREO, "SNDCTL_DSP_STEREO"},
-	{SNDCTL_DSP_GETBLKSIZE, "SNDCTL_DSP_GETBLKSIZE"},
-	{SNDCTL_DSP_SAMPLESIZE, "SNDCTL_DSP_SAMPLESIZE"},
-	{SNDCTL_DSP_CHANNELS, "SNDCTL_DSP_CHANNELS"},
-	{SOUND_PCM_WRITE_CHANNELS, "SOUND_PCM_WRITE_CHANNELS"},
-	{SOUND_PCM_WRITE_FILTER, "SOUND_PCM_WRITE_FILTER"},
-	{SNDCTL_DSP_POST, "SNDCTL_DSP_POST"},
-	{SNDCTL_DSP_SUBDIVIDE, "SNDCTL_DSP_SUBDIVIDE"},
-	{SNDCTL_DSP_SETFRAGMENT, "SNDCTL_DSP_SETFRAGMENT"},
-	{SNDCTL_DSP_GETFMTS, "SNDCTL_DSP_GETFMTS"},
-	{SNDCTL_DSP_SETFMT, "SNDCTL_DSP_SETFMT"},
-	{SNDCTL_DSP_GETOSPACE, "SNDCTL_DSP_GETOSPACE"},
-	{SNDCTL_DSP_GETISPACE, "SNDCTL_DSP_GETISPACE"},
-	{SNDCTL_DSP_NONBLOCK, "SNDCTL_DSP_NONBLOCK"},
-	{SNDCTL_DSP_GETCAPS, "SNDCTL_DSP_GETCAPS"},
-	{SNDCTL_DSP_GETTRIGGER, "SNDCTL_DSP_GETTRIGGER"},
-	{SNDCTL_DSP_SETTRIGGER, "SNDCTL_DSP_SETTRIGGER"},
-	{SNDCTL_DSP_GETIPTR, "SNDCTL_DSP_GETIPTR"},
-	{SNDCTL_DSP_GETOPTR, "SNDCTL_DSP_GETOPTR"},
-	{SNDCTL_DSP_MAPINBUF, "SNDCTL_DSP_MAPINBUF"},
-	{SNDCTL_DSP_MAPOUTBUF, "SNDCTL_DSP_MAPOUTBUF"},
-	{SNDCTL_DSP_SETSYNCRO, "SNDCTL_DSP_SETSYNCRO"},
-	{SNDCTL_DSP_SETDUPLEX, "SNDCTL_DSP_SETDUPLEX"},
-	{SNDCTL_DSP_GETODELAY, "SNDCTL_DSP_GETODELAY"},
-	{SNDCTL_DSP_GETCHANNELMASK, "SNDCTL_DSP_GETCHANNELMASK"},
-	{SNDCTL_DSP_BIND_CHANNEL, "SNDCTL_DSP_BIND_CHANNEL"},
-	{OSS_GETVERSION, "OSS_GETVERSION"},
-	{SOUND_PCM_READ_RATE, "SOUND_PCM_READ_RATE"},
-	{SOUND_PCM_READ_CHANNELS, "SOUND_PCM_READ_CHANNELS"},
-	{SOUND_PCM_READ_BITS, "SOUND_PCM_READ_BITS"},
-	{SOUND_PCM_READ_FILTER, "SOUND_PCM_READ_FILTER"}
-};
-#endif
-
-static int
-dma_count_done(struct dmabuf *db)
-{
-	if (db->stopped)
-		return 0;
-
-	return db->dma_fragsize - au1xxx_get_dma_residue(db->dmanr);
-}
-
-
-static int
-au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct au1550_state *s = file->private_data;
-	unsigned long   flags;
-	audio_buf_info  abinfo;
-	count_info      cinfo;
-	int             count;
-	int             val, mapped, ret, diff;
-
-	mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
-		((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
-
-#ifdef DEBUG
-	for (count = 0; count < ARRAY_SIZE(ioctl_str); count++) {
-		if (ioctl_str[count].cmd == cmd)
-			break;
-	}
-	if (count < ARRAY_SIZE(ioctl_str))
-		pr_debug("ioctl %s, arg=0x%lxn", ioctl_str[count].str, arg);
-	else
-		pr_debug("ioctl 0x%x unknown, arg=0x%lx\n", cmd, arg);
-#endif
-
-	switch (cmd) {
-	case OSS_GETVERSION:
-		return put_user(SOUND_VERSION, (int *) arg);
-
-	case SNDCTL_DSP_SYNC:
-		if (file->f_mode & FMODE_WRITE)
-			return drain_dac(s, file->f_flags & O_NONBLOCK);
-		return 0;
-
-	case SNDCTL_DSP_SETDUPLEX:
-		return 0;
-
-	case SNDCTL_DSP_GETCAPS:
-		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME |
-				DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
-
-	case SNDCTL_DSP_RESET:
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			synchronize_irq();
-			s->dma_dac.count = s->dma_dac.total_bytes = 0;
-			s->dma_dac.nextIn = s->dma_dac.nextOut =
-				s->dma_dac.rawbuf;
-		}
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			synchronize_irq();
-			s->dma_adc.count = s->dma_adc.total_bytes = 0;
-			s->dma_adc.nextIn = s->dma_adc.nextOut =
-				s->dma_adc.rawbuf;
-		}
-		return 0;
-
-	case SNDCTL_DSP_SPEED:
-		if (get_user(val, (int *) arg))
-			return -EFAULT;
-		if (val >= 0) {
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				set_adc_rate(s, val);
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(s);
-				set_dac_rate(s, val);
-			}
-			if (s->open_mode & FMODE_READ)
-				if ((ret = prog_dmabuf_adc(s)))
-					return ret;
-			if (s->open_mode & FMODE_WRITE)
-				if ((ret = prog_dmabuf_dac(s)))
-					return ret;
-		}
-		return put_user((file->f_mode & FMODE_READ) ?
-				s->dma_adc.sample_rate :
-				s->dma_dac.sample_rate,
-				(int *)arg);
-
-	case SNDCTL_DSP_STEREO:
-		if (get_user(val, (int *) arg))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			s->dma_adc.num_channels = val ? 2 : 1;
-			if ((ret = prog_dmabuf_adc(s)))
-				return ret;
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			s->dma_dac.num_channels = val ? 2 : 1;
-			if (s->codec_ext_caps & AC97_EXT_DACS) {
-				/* disable surround and center/lfe in AC'97
-				*/
-				u16 ext_stat = rdcodec(s->codec,
-						       AC97_EXTENDED_STATUS);
-				wrcodec(s->codec, AC97_EXTENDED_STATUS,
-					ext_stat | (AC97_EXTSTAT_PRI |
-						    AC97_EXTSTAT_PRJ |
-						    AC97_EXTSTAT_PRK));
-			}
-			if ((ret = prog_dmabuf_dac(s)))
-				return ret;
-		}
-		return 0;
-
-	case SNDCTL_DSP_CHANNELS:
-		if (get_user(val, (int *) arg))
-			return -EFAULT;
-		if (val != 0) {
-			if (file->f_mode & FMODE_READ) {
-				if (val < 0 || val > 2)
-					return -EINVAL;
-				stop_adc(s);
-				s->dma_adc.num_channels = val;
-				if ((ret = prog_dmabuf_adc(s)))
-					return ret;
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				switch (val) {
-				case 1:
-				case 2:
-					break;
-				case 3:
-				case 5:
-					return -EINVAL;
-				case 4:
-					if (!(s->codec_ext_caps &
-					      AC97_EXTID_SDAC))
-						return -EINVAL;
-					break;
-				case 6:
-					if ((s->codec_ext_caps &
-					     AC97_EXT_DACS) != AC97_EXT_DACS)
-						return -EINVAL;
-					break;
-				default:
-					return -EINVAL;
-				}
-
-				stop_dac(s);
-				if (val <= 2 &&
-				    (s->codec_ext_caps & AC97_EXT_DACS)) {
-					/* disable surround and center/lfe
-					 * channels in AC'97
-					 */
-					u16             ext_stat =
-						rdcodec(s->codec,
-							AC97_EXTENDED_STATUS);
-					wrcodec(s->codec,
-						AC97_EXTENDED_STATUS,
-						ext_stat | (AC97_EXTSTAT_PRI |
-							    AC97_EXTSTAT_PRJ |
-							    AC97_EXTSTAT_PRK));
-				} else if (val >= 4) {
-					/* enable surround, center/lfe
-					 * channels in AC'97
-					 */
-					u16             ext_stat =
-						rdcodec(s->codec,
-							AC97_EXTENDED_STATUS);
-					ext_stat &= ~AC97_EXTSTAT_PRJ;
-					if (val == 6)
-						ext_stat &=
-							~(AC97_EXTSTAT_PRI |
-							  AC97_EXTSTAT_PRK);
-					wrcodec(s->codec,
-						AC97_EXTENDED_STATUS,
-						ext_stat);
-				}
-
-				s->dma_dac.num_channels = val;
-				if ((ret = prog_dmabuf_dac(s)))
-					return ret;
-			}
-		}
-		return put_user(val, (int *) arg);
-
-	case SNDCTL_DSP_GETFMTS:	/* Returns a mask */
-		return put_user(AFMT_S16_LE | AFMT_U8, (int *) arg);
-
-	case SNDCTL_DSP_SETFMT:	/* Selects ONE fmt */
-		if (get_user(val, (int *) arg))
-			return -EFAULT;
-		if (val != AFMT_QUERY) {
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				if (val == AFMT_S16_LE)
-					s->dma_adc.sample_size = 16;
-				else {
-					val = AFMT_U8;
-					s->dma_adc.sample_size = 8;
-				}
-				if ((ret = prog_dmabuf_adc(s)))
-					return ret;
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(s);
-				if (val == AFMT_S16_LE)
-					s->dma_dac.sample_size = 16;
-				else {
-					val = AFMT_U8;
-					s->dma_dac.sample_size = 8;
-				}
-				if ((ret = prog_dmabuf_dac(s)))
-					return ret;
-			}
-		} else {
-			if (file->f_mode & FMODE_READ)
-				val = (s->dma_adc.sample_size == 16) ?
-					AFMT_S16_LE : AFMT_U8;
-			else
-				val = (s->dma_dac.sample_size == 16) ?
-					AFMT_S16_LE : AFMT_U8;
-		}
-		return put_user(val, (int *) arg);
-
-	case SNDCTL_DSP_POST:
-		return 0;
-
-	case SNDCTL_DSP_GETTRIGGER:
-		val = 0;
-		spin_lock_irqsave(&s->lock, flags);
-		if (file->f_mode & FMODE_READ && !s->dma_adc.stopped)
-			val |= PCM_ENABLE_INPUT;
-		if (file->f_mode & FMODE_WRITE && !s->dma_dac.stopped)
-			val |= PCM_ENABLE_OUTPUT;
-		spin_unlock_irqrestore(&s->lock, flags);
-		return put_user(val, (int *) arg);
-
-	case SNDCTL_DSP_SETTRIGGER:
-		if (get_user(val, (int *) arg))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			if (val & PCM_ENABLE_INPUT) {
-				spin_lock_irqsave(&s->lock, flags);
-				start_adc(s);
-				spin_unlock_irqrestore(&s->lock, flags);
-			} else
-				stop_adc(s);
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			if (val & PCM_ENABLE_OUTPUT) {
-				spin_lock_irqsave(&s->lock, flags);
-				start_dac(s);
-				spin_unlock_irqrestore(&s->lock, flags);
-			} else
-				stop_dac(s);
-		}
-		return 0;
-
-	case SNDCTL_DSP_GETOSPACE:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		abinfo.fragsize = s->dma_dac.fragsize;
-		spin_lock_irqsave(&s->lock, flags);
-		count = s->dma_dac.count;
-		count -= dma_count_done(&s->dma_dac);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count < 0)
-			count = 0;
-		abinfo.bytes = (s->dma_dac.dmasize - count) /
-			s->dma_dac.cnt_factor;
-		abinfo.fragstotal = s->dma_dac.numfrag;
-		abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
-		pr_debug("ioctl SNDCTL_DSP_GETOSPACE: bytes=%d, fragments=%d\n", abinfo.bytes, abinfo.fragments);
-		return copy_to_user((void *) arg, &abinfo,
-				    sizeof(abinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_GETISPACE:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		abinfo.fragsize = s->dma_adc.fragsize;
-		spin_lock_irqsave(&s->lock, flags);
-		count = s->dma_adc.count;
-		count += dma_count_done(&s->dma_adc);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count < 0)
-			count = 0;
-		abinfo.bytes = count / s->dma_adc.cnt_factor;
-		abinfo.fragstotal = s->dma_adc.numfrag;
-		abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
-		return copy_to_user((void *) arg, &abinfo,
-				    sizeof(abinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_NONBLOCK:
-		spin_lock(&file->f_lock);
-		file->f_flags |= O_NONBLOCK;
-		spin_unlock(&file->f_lock);
-		return 0;
-
-	case SNDCTL_DSP_GETODELAY:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		spin_lock_irqsave(&s->lock, flags);
-		count = s->dma_dac.count;
-		count -= dma_count_done(&s->dma_dac);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count < 0)
-			count = 0;
-		count /= s->dma_dac.cnt_factor;
-		return put_user(count, (int *) arg);
-
-	case SNDCTL_DSP_GETIPTR:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		spin_lock_irqsave(&s->lock, flags);
-		cinfo.bytes = s->dma_adc.total_bytes;
-		count = s->dma_adc.count;
-		if (!s->dma_adc.stopped) {
-			diff = dma_count_done(&s->dma_adc);
-			count += diff;
-			cinfo.bytes += diff;
-			cinfo.ptr =  virt_to_phys(s->dma_adc.nextIn) + diff -
-				virt_to_phys(s->dma_adc.rawbuf);
-		} else
-			cinfo.ptr = virt_to_phys(s->dma_adc.nextIn) -
-				virt_to_phys(s->dma_adc.rawbuf);
-		if (s->dma_adc.mapped)
-			s->dma_adc.count &= (s->dma_adc.dma_fragsize-1);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count < 0)
-			count = 0;
-		cinfo.blocks = count >> s->dma_adc.fragshift;
-		return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
-
-	case SNDCTL_DSP_GETOPTR:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		spin_lock_irqsave(&s->lock, flags);
-		cinfo.bytes = s->dma_dac.total_bytes;
-		count = s->dma_dac.count;
-		if (!s->dma_dac.stopped) {
-			diff = dma_count_done(&s->dma_dac);
-			count -= diff;
-			cinfo.bytes += diff;
-			cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) + diff -
-				virt_to_phys(s->dma_dac.rawbuf);
-		} else
-			cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) -
-				virt_to_phys(s->dma_dac.rawbuf);
-		if (s->dma_dac.mapped)
-			s->dma_dac.count &= (s->dma_dac.dma_fragsize-1);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count < 0)
-			count = 0;
-		cinfo.blocks = count >> s->dma_dac.fragshift;
-		return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
-
-	case SNDCTL_DSP_GETBLKSIZE:
-		if (file->f_mode & FMODE_WRITE)
-			return put_user(s->dma_dac.fragsize, (int *) arg);
-		else
-			return put_user(s->dma_adc.fragsize, (int *) arg);
-
-	case SNDCTL_DSP_SETFRAGMENT:
-		if (get_user(val, (int *) arg))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			s->dma_adc.ossfragshift = val & 0xffff;
-			s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
-			if (s->dma_adc.ossfragshift < 4)
-				s->dma_adc.ossfragshift = 4;
-			if (s->dma_adc.ossfragshift > 15)
-				s->dma_adc.ossfragshift = 15;
-			if (s->dma_adc.ossmaxfrags < 4)
-				s->dma_adc.ossmaxfrags = 4;
-			if ((ret = prog_dmabuf_adc(s)))
-				return ret;
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			s->dma_dac.ossfragshift = val & 0xffff;
-			s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
-			if (s->dma_dac.ossfragshift < 4)
-				s->dma_dac.ossfragshift = 4;
-			if (s->dma_dac.ossfragshift > 15)
-				s->dma_dac.ossfragshift = 15;
-			if (s->dma_dac.ossmaxfrags < 4)
-				s->dma_dac.ossmaxfrags = 4;
-			if ((ret = prog_dmabuf_dac(s)))
-				return ret;
-		}
-		return 0;
-
-	case SNDCTL_DSP_SUBDIVIDE:
-		if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
-		    (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
-			return -EINVAL;
-		if (get_user(val, (int *) arg))
-			return -EFAULT;
-		if (val != 1 && val != 2 && val != 4)
-			return -EINVAL;
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			s->dma_adc.subdivision = val;
-			if ((ret = prog_dmabuf_adc(s)))
-				return ret;
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			s->dma_dac.subdivision = val;
-			if ((ret = prog_dmabuf_dac(s)))
-				return ret;
-		}
-		return 0;
-
-	case SOUND_PCM_READ_RATE:
-		return put_user((file->f_mode & FMODE_READ) ?
-				s->dma_adc.sample_rate :
-				s->dma_dac.sample_rate,
-				(int *)arg);
-
-	case SOUND_PCM_READ_CHANNELS:
-		if (file->f_mode & FMODE_READ)
-			return put_user(s->dma_adc.num_channels, (int *)arg);
-		else
-			return put_user(s->dma_dac.num_channels, (int *)arg);
-
-	case SOUND_PCM_READ_BITS:
-		if (file->f_mode & FMODE_READ)
-			return put_user(s->dma_adc.sample_size, (int *)arg);
-		else
-			return put_user(s->dma_dac.sample_size, (int *)arg);
-
-	case SOUND_PCM_WRITE_FILTER:
-	case SNDCTL_DSP_SETSYNCRO:
-	case SOUND_PCM_READ_FILTER:
-		return -EINVAL;
-	}
-
-	return mixdev_ioctl(s->codec, cmd, arg);
-}
-
-static long
-au1550_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-	int ret;
-
-	mutex_lock(&au1550_ac97_mutex);
-	ret = au1550_ioctl(file, cmd, arg);
-	mutex_unlock(&au1550_ac97_mutex);
-
-	return ret;
-}
-
-static int
-au1550_open(struct inode *inode, struct file *file)
-{
-	int             minor = MINOR(inode->i_rdev);
-	DECLARE_WAITQUEUE(wait, current);
-	struct au1550_state *s = &au1550_state;
-	int             ret;
-
-#ifdef DEBUG
-	if (file->f_flags & O_NONBLOCK)
-		pr_debug("open: non-blocking\n");
-	else
-		pr_debug("open: blocking\n");
-#endif
-
-	file->private_data = s;
-	mutex_lock(&au1550_ac97_mutex);
-	/* wait for device to become free */
-	mutex_lock(&s->open_mutex);
-	while (s->open_mode & file->f_mode) {
-		ret = -EBUSY;
-		if (file->f_flags & O_NONBLOCK)
-			goto out;
-		add_wait_queue(&s->open_wait, &wait);
-		__set_current_state(TASK_INTERRUPTIBLE);
-		mutex_unlock(&s->open_mutex);
-		schedule();
-		remove_wait_queue(&s->open_wait, &wait);
-		set_current_state(TASK_RUNNING);
-		ret = -ERESTARTSYS;
-		if (signal_pending(current))
-			goto out2;
-		mutex_lock(&s->open_mutex);
-	}
-
-	stop_dac(s);
-	stop_adc(s);
-
-	if (file->f_mode & FMODE_READ) {
-		s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags =
-			s->dma_adc.subdivision = s->dma_adc.total_bytes = 0;
-		s->dma_adc.num_channels = 1;
-		s->dma_adc.sample_size = 8;
-		set_adc_rate(s, 8000);
-		if ((minor & 0xf) == SND_DEV_DSP16)
-			s->dma_adc.sample_size = 16;
-	}
-
-	if (file->f_mode & FMODE_WRITE) {
-		s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags =
-			s->dma_dac.subdivision = s->dma_dac.total_bytes = 0;
-		s->dma_dac.num_channels = 1;
-		s->dma_dac.sample_size = 8;
-		set_dac_rate(s, 8000);
-		if ((minor & 0xf) == SND_DEV_DSP16)
-			s->dma_dac.sample_size = 16;
-	}
-
-	if (file->f_mode & FMODE_READ) {
-		if ((ret = prog_dmabuf_adc(s)))
-			goto out;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		if ((ret = prog_dmabuf_dac(s)))
-			goto out;
-	}
-
-	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-	mutex_init(&s->sem);
-	ret = 0;
-out:
-	mutex_unlock(&s->open_mutex);
-out2:
-	mutex_unlock(&au1550_ac97_mutex);
-	return ret;
-}
-
-static int
-au1550_release(struct inode *inode, struct file *file)
-{
-	struct au1550_state *s = file->private_data;
-
-	mutex_lock(&au1550_ac97_mutex);
-
-	if (file->f_mode & FMODE_WRITE) {
-		mutex_unlock(&au1550_ac97_mutex);
-		drain_dac(s, file->f_flags & O_NONBLOCK);
-		mutex_lock(&au1550_ac97_mutex);
-	}
-
-	mutex_lock(&s->open_mutex);
-	if (file->f_mode & FMODE_WRITE) {
-		stop_dac(s);
-		kfree(s->dma_dac.rawbuf);
-		s->dma_dac.rawbuf = NULL;
-	}
-	if (file->f_mode & FMODE_READ) {
-		stop_adc(s);
-		kfree(s->dma_adc.rawbuf);
-		s->dma_adc.rawbuf = NULL;
-	}
-	s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE));
-	mutex_unlock(&s->open_mutex);
-	wake_up(&s->open_wait);
-	mutex_unlock(&au1550_ac97_mutex);
-	return 0;
-}
-
-static /*const */ struct file_operations au1550_audio_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= au1550_llseek,
-	.read		= au1550_read,
-	.write		= au1550_write,
-	.poll		= au1550_poll,
-	.unlocked_ioctl	= au1550_unlocked_ioctl,
-	.mmap		= au1550_mmap,
-	.open		= au1550_open,
-	.release	= au1550_release,
-};
-
-MODULE_AUTHOR("Advanced Micro Devices (AMD), dan@embeddededge.com");
-MODULE_DESCRIPTION("Au1550 AC97 Audio Driver");
-MODULE_LICENSE("GPL");
-
-
-static int __devinit
-au1550_probe(void)
-{
-	struct au1550_state *s = &au1550_state;
-	int             val;
-
-	memset(s, 0, sizeof(struct au1550_state));
-
-	init_waitqueue_head(&s->dma_adc.wait);
-	init_waitqueue_head(&s->dma_dac.wait);
-	init_waitqueue_head(&s->open_wait);
-	mutex_init(&s->open_mutex);
-	spin_lock_init(&s->lock);
-
-	s->codec = ac97_alloc_codec();
-	if(s->codec == NULL) {
-		err("Out of memory");
-		return -1;
-	}
-	s->codec->private_data = s;
-	s->codec->id = 0;
-	s->codec->codec_read = rdcodec;
-	s->codec->codec_write = wrcodec;
-	s->codec->codec_wait = waitcodec;
-
-	if (!request_mem_region(CPHYSADDR(AC97_PSC_SEL),
-			    0x30, "Au1550 AC97")) {
-		err("AC'97 ports in use");
-	}
-
-	/* Allocate the DMA Channels
-	*/
-	if ((s->dma_dac.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_MEM_CHAN,
-	    DBDMA_AC97_TX_CHAN, dac_dma_interrupt, (void *)s)) == 0) {
-		err("Can't get DAC DMA");
-		goto err_dma1;
-	}
-	au1xxx_dbdma_set_devwidth(s->dma_dac.dmanr, 16);
-	if (au1xxx_dbdma_ring_alloc(s->dma_dac.dmanr,
-					NUM_DBDMA_DESCRIPTORS) == 0) {
-		err("Can't get DAC DMA descriptors");
-		goto err_dma1;
-	}
-
-	if ((s->dma_adc.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_AC97_RX_CHAN,
-	    DBDMA_MEM_CHAN, adc_dma_interrupt, (void *)s)) == 0) {
-		err("Can't get ADC DMA");
-		goto err_dma2;
-	}
-	au1xxx_dbdma_set_devwidth(s->dma_adc.dmanr, 16);
-	if (au1xxx_dbdma_ring_alloc(s->dma_adc.dmanr,
-					NUM_DBDMA_DESCRIPTORS) == 0) {
-		err("Can't get ADC DMA descriptors");
-		goto err_dma2;
-	}
-
-	pr_info("DAC: DMA%d, ADC: DMA%d", DBDMA_AC97_TX_CHAN, DBDMA_AC97_RX_CHAN);
-
-	/* register devices */
-
-	if ((s->dev_audio = register_sound_dsp(&au1550_audio_fops, -1)) < 0)
-		goto err_dev1;
-	if ((s->codec->dev_mixer =
-	     register_sound_mixer(&au1550_mixer_fops, -1)) < 0)
-		goto err_dev2;
-
-	/* The GPIO for the appropriate PSC was configured by the
-	 * board specific start up.
-	 *
-	 * configure PSC for AC'97
-	 */
-	au_writel(0, AC97_PSC_CTRL);	/* Disable PSC */
-	au_sync();
-	au_writel((PSC_SEL_CLK_SERCLK | PSC_SEL_PS_AC97MODE), AC97_PSC_SEL);
-	au_sync();
-
-	/* cold reset the AC'97
-	*/
-	au_writel(PSC_AC97RST_RST, PSC_AC97RST);
-	au_sync();
-	au1550_delay(10);
-	au_writel(0, PSC_AC97RST);
-	au_sync();
-
-	/* need to delay around 500msec(bleech) to give
-	   some CODECs enough time to wakeup */
-	au1550_delay(500);
-
-	/* warm reset the AC'97 to start the bitclk
-	*/
-	au_writel(PSC_AC97RST_SNC, PSC_AC97RST);
-	au_sync();
-	udelay(100);
-	au_writel(0, PSC_AC97RST);
-	au_sync();
-
-	/* Enable PSC
-	*/
-	au_writel(PSC_CTRL_ENABLE, AC97_PSC_CTRL);
-	au_sync();
-
-	/* Wait for PSC ready.
-	*/
-	do {
-		val = au_readl(PSC_AC97STAT);
-		au_sync();
-	} while ((val & PSC_AC97STAT_SR) == 0);
-
-	/* Configure AC97 controller.
-	 * Deep FIFO, 16-bit sample, DMA, make sure DMA matches fifo size.
-	 */
-	val = PSC_AC97CFG_SET_LEN(16);
-	val |= PSC_AC97CFG_RT_FIFO8 | PSC_AC97CFG_TT_FIFO8;
-
-	/* Enable device so we can at least
-	 * talk over the AC-link.
-	 */
-	au_writel(val, PSC_AC97CFG);
-	au_writel(PSC_AC97MSK_ALLMASK, PSC_AC97MSK);
-	au_sync();
-	val |= PSC_AC97CFG_DE_ENABLE;
-	au_writel(val, PSC_AC97CFG);
-	au_sync();
-
-	/* Wait for Device ready.
-	*/
-	do {
-		val = au_readl(PSC_AC97STAT);
-		au_sync();
-	} while ((val & PSC_AC97STAT_DR) == 0);
-
-	/* codec init */
-	if (!ac97_probe_codec(s->codec))
-		goto err_dev3;
-
-	s->codec_base_caps = rdcodec(s->codec, AC97_RESET);
-	s->codec_ext_caps = rdcodec(s->codec, AC97_EXTENDED_ID);
-	pr_info("AC'97 Base/Extended ID = %04x/%04x",
-	     s->codec_base_caps, s->codec_ext_caps);
-
-	if (!(s->codec_ext_caps & AC97_EXTID_VRA)) {
-		/* codec does not support VRA
-		*/
-		s->no_vra = 1;
-	} else if (!vra) {
-		/* Boot option says disable VRA
-		*/
-		u16 ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS);
-		wrcodec(s->codec, AC97_EXTENDED_STATUS,
-			ac97_extstat & ~AC97_EXTSTAT_VRA);
-		s->no_vra = 1;
-	}
-	if (s->no_vra)
-		pr_info("no VRA, interpolating and decimating");
-
-	/* set mic to be the recording source */
-	val = SOUND_MASK_MIC;
-	mixdev_ioctl(s->codec, SOUND_MIXER_WRITE_RECSRC,
-		     (unsigned long) &val);
-
-	return 0;
-
- err_dev3:
-	unregister_sound_mixer(s->codec->dev_mixer);
- err_dev2:
-	unregister_sound_dsp(s->dev_audio);
- err_dev1:
-	au1xxx_dbdma_chan_free(s->dma_adc.dmanr);
- err_dma2:
-	au1xxx_dbdma_chan_free(s->dma_dac.dmanr);
- err_dma1:
-	release_mem_region(CPHYSADDR(AC97_PSC_SEL), 0x30);
-
-	ac97_release_codec(s->codec);
-	return -1;
-}
-
-static void __devinit
-au1550_remove(void)
-{
-	struct au1550_state *s = &au1550_state;
-
-	if (!s)
-		return;
-	synchronize_irq();
-	au1xxx_dbdma_chan_free(s->dma_adc.dmanr);
-	au1xxx_dbdma_chan_free(s->dma_dac.dmanr);
-	release_mem_region(CPHYSADDR(AC97_PSC_SEL), 0x30);
-	unregister_sound_dsp(s->dev_audio);
-	unregister_sound_mixer(s->codec->dev_mixer);
-	ac97_release_codec(s->codec);
-}
-
-static int __init
-init_au1550(void)
-{
-	return au1550_probe();
-}
-
-static void __exit
-cleanup_au1550(void)
-{
-	au1550_remove();
-}
-
-module_init(init_au1550);
-module_exit(cleanup_au1550);
-
-#ifndef MODULE
-
-static int __init
-au1550_setup(char *options)
-{
-	char           *this_opt;
-
-	if (!options || !*options)
-		return 0;
-
-	while ((this_opt = strsep(&options, ","))) {
-		if (!*this_opt)
-			continue;
-		if (!strncmp(this_opt, "vra", 3)) {
-			vra = 1;
-		}
-	}
-
-	return 1;
-}
-
-__setup("au1550_audio=", au1550_setup);
-
-#endif /* MODULE */
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 389cd7931668..e90d103e177e 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -534,6 +534,14 @@ config SND_ES1968_INPUT
 	  If you say N the buttons will directly control the master volume.
 	  It is recommended to say Y.
 
+config SND_ES1968_RADIO
+	bool "Enable TEA5757 radio tuner support for es1968"
+	depends on SND_ES1968
+	depends on VIDEO_V4L2=y || VIDEO_V4L2=SND_ES1968
+	help
+	  Say Y here to include support for TEA5757 radio tuner integrated on
+	  some MediaForte cards (e.g. SF64-PCE2).
+
 config SND_FM801
 	tristate "ForteMedia FM801"
 	select SND_OPL3_LIB
@@ -552,13 +560,13 @@ config SND_FM801_TEA575X_BOOL
 	depends on VIDEO_V4L2=y || VIDEO_V4L2=SND_FM801
 	help
 	  Say Y here to include support for soundcards based on the ForteMedia
-	  FM801 chip with a TEA5757 tuner connected to GPIO1-3 pins (Media
-	  Forte SF256-PCS-02) into the snd-fm801 driver.
+	  FM801 chip with a TEA5757 tuner (MediaForte SF256-PCS, SF256-PCP and
+	  SF64-PCR) into the snd-fm801 driver.
 
-config SND_FM801_TEA575X
+config SND_TEA575X
 	tristate
-	depends on SND_FM801_TEA575X_BOOL
-	default SND_FM801
+	depends on SND_FM801_TEA575X_BOOL || SND_ES1968_RADIO
+	default SND_FM801 || SND_ES1968
 
 source "sound/pci/hda/Kconfig"
 
@@ -658,6 +666,15 @@ config SND_KORG1212
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-korg1212.
 
+config SND_LOLA
+	tristate "Digigram Lola"
+	select SND_PCM
+	help
+	  Say Y to include support for Digigram Lola boards.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-lola.
+
 config SND_LX6464ES
 	tristate "Digigram LX6464ES"
 	select SND_PCM
diff --git a/sound/pci/Makefile b/sound/pci/Makefile
index 9cf4348ec137..54fe325e3aa5 100644
--- a/sound/pci/Makefile
+++ b/sound/pci/Makefile
@@ -64,6 +64,7 @@ obj-$(CONFIG_SND) += \
 	ca0106/ \
 	cs46xx/ \
 	cs5535audio/ \
+	lola/ \
 	lx6464es/ \
 	echoaudio/ \
 	emu10k1/ \
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index f8ccc9677c6f..2ca6f4f85b41 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -42,10 +42,29 @@
 #include <sound/tlv.h>
 #include <sound/hwdep.h>
 
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>");
 MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx");
 
+#if defined CONFIG_SND_DEBUG
+/* copied from pcm_lib.c, hope later patch will make that version public
+and this copy can be removed */
+static void pcm_debug_name(struct snd_pcm_substream *substream,
+			   char *name, size_t len)
+{
+	snprintf(name, len, "pcmC%dD%d%c:%d",
+		 substream->pcm->card->number,
+		 substream->pcm->device,
+		 substream->stream ? 'c' : 'p',
+		 substream->number);
+}
+#define DEBUG_NAME(substream, name) char name[16]; pcm_debug_name(substream, name, sizeof(name))
+#else
+#define pcm_debug_name(s, n, l) do { } while (0)
+#define DEBUG_NAME(name, substream) do { } while (0)
+#endif
+
 #if defined CONFIG_SND_DEBUG_VERBOSE
 /**
  * snd_printddd - very verbose debug printk
@@ -58,7 +77,7 @@ MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx");
 #define snd_printddd(format, args...) \
 	__snd_printk(3, __FILE__, __LINE__, format, ##args)
 #else
-#define snd_printddd(format, args...)	do { } while (0)
+#define snd_printddd(format, args...) do { } while (0)
 #endif
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* index 0-MAX */
@@ -101,13 +120,6 @@ static int adapter_fs = DEFAULT_SAMPLERATE;
 #define PERIOD_BYTES_MIN  2048
 #define BUFFER_BYTES_MAX (512 * 1024)
 
-/* convert stream to character */
-#define SCHR(s) ((s == SNDRV_PCM_STREAM_PLAYBACK) ? 'P' : 'C')
-
-/*#define TIMER_MILLISECONDS 20
-#define FORCE_TIMER_JIFFIES ((TIMER_MILLISECONDS * HZ + 999)/1000)
-*/
-
 #define MAX_CLOCKSOURCES (HPI_SAMPLECLOCK_SOURCE_LAST + 1 + 7)
 
 struct clk_source {
@@ -136,7 +148,7 @@ struct snd_card_asihpi {
 	u32 h_mixer;
 	struct clk_cache cc;
 
-	u16 support_mmap;
+	u16 can_dma;
 	u16 support_grouping;
 	u16 support_mrx;
 	u16 update_interval_frames;
@@ -155,6 +167,7 @@ struct snd_card_asihpi_pcm {
 	unsigned int pcm_buf_host_rw_ofs; /* Host R/W pos */
 	unsigned int pcm_buf_dma_ofs;	/* DMA R/W offset in buffer */
 	unsigned int pcm_buf_elapsed_dma_ofs;	/* DMA R/W offset in buffer */
+	unsigned int drained_count;
 	struct snd_pcm_substream *substream;
 	u32 h_stream;
 	struct hpi_format format;
@@ -288,19 +301,26 @@ static u16 handle_error(u16 err, int line, char *filename)
 #define hpi_handle_error(x)  handle_error(x, __LINE__, __FILE__)
 
 /***************************** GENERAL PCM ****************/
-static void print_hwparams(struct snd_pcm_hw_params *p)
+
+static void print_hwparams(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *p)
 {
-	snd_printd("HWPARAMS \n");
-	snd_printd("samplerate %d \n", params_rate(p));
-	snd_printd("Channels %d \n", params_channels(p));
-	snd_printd("Format %d \n", params_format(p));
-	snd_printd("subformat %d \n", params_subformat(p));
-	snd_printd("Buffer bytes %d \n", params_buffer_bytes(p));
-	snd_printd("Period bytes %d \n", params_period_bytes(p));
-	snd_printd("access %d \n", params_access(p));
-	snd_printd("period_size %d \n", params_period_size(p));
-	snd_printd("periods %d \n", params_periods(p));
-	snd_printd("buffer_size %d \n", params_buffer_size(p));
+	DEBUG_NAME(substream, name);
+	snd_printd("%s HWPARAMS\n", name);
+	snd_printd(" samplerate %d Hz\n", params_rate(p));
+	snd_printd(" channels %d\n", params_channels(p));
+	snd_printd(" format %d\n", params_format(p));
+	snd_printd(" subformat %d\n", params_subformat(p));
+	snd_printd(" buffer %d B\n", params_buffer_bytes(p));
+	snd_printd(" period %d B\n", params_period_bytes(p));
+	snd_printd(" access %d\n", params_access(p));
+	snd_printd(" period_size %d\n", params_period_size(p));
+	snd_printd(" periods %d\n", params_periods(p));
+	snd_printd(" buffer_size %d\n", params_buffer_size(p));
+	snd_printd(" %d B/s\n", params_rate(p) *
+		params_channels(p) *
+		snd_pcm_format_width(params_format(p)) / 8);
+
 }
 
 static snd_pcm_format_t hpi_to_alsa_formats[] = {
@@ -451,7 +471,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
 	int width;
 	unsigned int bytes_per_sec;
 
-	print_hwparams(params);
+	print_hwparams(substream, params);
 	err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
 	if (err < 0)
 		return err;
@@ -459,10 +479,6 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
 	if (err)
 		return err;
 
-	snd_printdd("format %d, %d chans, %d_hz\n",
-				format, params_channels(params),
-				params_rate(params));
-
 	hpi_handle_error(hpi_format_create(&dpcm->format,
 			params_channels(params),
 			format, params_rate(params), 0, 0));
@@ -477,8 +493,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	dpcm->hpi_buffer_attached = 0;
-	if (card->support_mmap) {
-
+	if (card->can_dma) {
 		err = hpi_stream_host_buffer_attach(dpcm->h_stream,
 			params_buffer_bytes(params),  runtime->dma_addr);
 		if (err == 0) {
@@ -509,8 +524,6 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
 	dpcm->bytes_per_sec = bytes_per_sec;
 	dpcm->buffer_bytes = params_buffer_bytes(params);
 	dpcm->period_bytes = params_period_bytes(params);
-	snd_printdd("buffer_bytes=%d, period_bytes=%d, bps=%d\n",
-			dpcm->buffer_bytes, dpcm->period_bytes, bytes_per_sec);
 
 	return 0;
 }
@@ -564,9 +577,10 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
 	struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
 	struct snd_pcm_substream *s;
 	u16 e;
+	DEBUG_NAME(substream, name);
+
+	snd_printdd("%s trigger\n", name);
 
-	snd_printdd("%c%d trigger\n",
-			SCHR(substream->stream), substream->number);
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 		snd_pcm_group_for_each_entry(s, substream) {
@@ -580,8 +594,8 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
 			if (substream->stream != s->stream)
 				continue;
 
-			if ((s->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
-				(card->support_mmap)) {
+			ds->drained_count = 0;
+			if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 				/* How do I know how much valid data is present
 				* in buffer? Must be at least one period!
 				* Guessing 2 periods, but if
@@ -599,9 +613,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
 			}
 
 			if (card->support_grouping) {
-				snd_printdd("\t%c%d group\n",
-						SCHR(s->stream),
-						s->number);
+				snd_printdd("%d group\n", s->number);
 				e = hpi_stream_group_add(
 					dpcm->h_stream,
 					ds->h_stream);
@@ -618,7 +630,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
 		/* start the master stream */
 		snd_card_asihpi_pcm_timer_start(substream);
 		if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ||
-			!card->support_mmap)
+			!card->can_dma)
 			hpi_handle_error(hpi_stream_start(dpcm->h_stream));
 		break;
 
@@ -636,9 +648,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
 			s->runtime->status->state = SNDRV_PCM_STATE_SETUP;
 
 			if (card->support_grouping) {
-				snd_printdd("\t%c%d group\n",
-				SCHR(s->stream),
-					s->number);
+				snd_printdd("%d group\n", s->number);
 				snd_pcm_trigger_done(s, substream);
 			} else
 				break;
@@ -732,9 +742,9 @@ static void snd_card_asihpi_timer_function(unsigned long data)
 	int loops = 0;
 	u16 state;
 	u32 buffer_size, bytes_avail, samples_played, on_card_bytes;
+	DEBUG_NAME(substream, name);
 
-	snd_printdd("%c%d snd_card_asihpi_timer_function\n",
-				SCHR(substream->stream), substream->number);
+	snd_printdd("%s snd_card_asihpi_timer_function\n", name);
 
 	/* find minimum newdata and buffer pos in group */
 	snd_pcm_group_for_each_entry(s, substream) {
@@ -756,6 +766,9 @@ static void snd_card_asihpi_timer_function(unsigned long data)
 		/* number of bytes in on-card buffer */
 		runtime->delay = on_card_bytes;
 
+		if (!card->can_dma)
+			on_card_bytes = bytes_avail;
+
 		if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 			pcm_buf_dma_ofs = ds->pcm_buf_host_rw_ofs - bytes_avail;
 			if (state == HPI_STATE_STOPPED) {
@@ -763,12 +776,18 @@ static void snd_card_asihpi_timer_function(unsigned long data)
 				    (on_card_bytes < ds->pcm_buf_host_rw_ofs)) {
 					hpi_handle_error(hpi_stream_start(ds->h_stream));
 					snd_printdd("P%d start\n", s->number);
+					ds->drained_count = 0;
 				}
 			} else if (state == HPI_STATE_DRAINED) {
 				snd_printd(KERN_WARNING "P%d drained\n",
 						s->number);
-				/*snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN);
-				continue; */
+				ds->drained_count++;
+				if (ds->drained_count > 2) {
+					snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN);
+					continue;
+				}
+			} else {
+				ds->drained_count = 0;
 			}
 		} else
 			pcm_buf_dma_ofs = bytes_avail + ds->pcm_buf_host_rw_ofs;
@@ -786,16 +805,18 @@ static void snd_card_asihpi_timer_function(unsigned long data)
 				newdata);
 		}
 
-		snd_printdd("hw_ptr x%04lX, appl_ptr x%04lX\n",
+		snd_printdd("hw_ptr 0x%04lX, appl_ptr 0x%04lX\n",
 			(unsigned long)frames_to_bytes(runtime,
 						runtime->status->hw_ptr),
 			(unsigned long)frames_to_bytes(runtime,
 						runtime->control->appl_ptr));
 
-		snd_printdd("%d %c%d S=%d, rw=%04X, dma=x%04X, left=x%04X,"
-			" aux=x%04X space=x%04X\n",
-			loops, SCHR(s->stream),	s->number,
-			state,	ds->pcm_buf_host_rw_ofs, pcm_buf_dma_ofs, (int)bytes_avail,
+		snd_printdd("%d S=%d, "
+			"rw=0x%04X, dma=0x%04X, left=0x%04X, "
+			"aux=0x%04X space=0x%04X\n",
+			s->number, state,
+			ds->pcm_buf_host_rw_ofs, pcm_buf_dma_ofs,
+			(int)bytes_avail,
 			(int)on_card_bytes, buffer_size-bytes_avail);
 		loops++;
 	}
@@ -814,7 +835,7 @@ static void snd_card_asihpi_timer_function(unsigned long data)
 
 	next_jiffies = max(next_jiffies, 1U);
 	dpcm->timer.expires = jiffies + next_jiffies;
-	snd_printdd("jif %d buf pos x%04X newdata x%04X xfer x%04X\n",
+	snd_printdd("jif %d buf pos 0x%04X newdata 0x%04X xfer 0x%04X\n",
 			next_jiffies, pcm_buf_dma_ofs, newdata, xfercount);
 
 	snd_pcm_group_for_each_entry(s, substream) {
@@ -826,30 +847,63 @@ static void snd_card_asihpi_timer_function(unsigned long data)
 
 		ds->pcm_buf_dma_ofs = pcm_buf_dma_ofs;
 
-		if (xfercount && (on_card_bytes <= ds->period_bytes)) {
-			if (card->support_mmap) {
-				if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-					snd_printddd("P%d write x%04x\n",
+		if (xfercount &&
+			/* Limit use of on card fifo for playback */
+			((on_card_bytes <= ds->period_bytes) ||
+			(s->stream == SNDRV_PCM_STREAM_CAPTURE)))
+
+		{
+
+			unsigned int buf_ofs = ds->pcm_buf_host_rw_ofs % ds->buffer_bytes;
+			unsigned int xfer1, xfer2;
+			char *pd = &s->runtime->dma_area[buf_ofs];
+
+			if (card->can_dma) { /* buffer wrap is handled at lower level */
+				xfer1 = xfercount;
+				xfer2 = 0;
+			} else {
+				xfer1 = min(xfercount, ds->buffer_bytes - buf_ofs);
+				xfer2 = xfercount - xfer1;
+			}
+
+			if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+				snd_printddd("P%d write1 0x%04X 0x%04X\n",
+					s->number, xfer1, buf_ofs);
+				hpi_handle_error(
+					hpi_outstream_write_buf(
+						ds->h_stream, pd, xfer1,
+						&ds->format));
+
+				if (xfer2) {
+					pd = s->runtime->dma_area;
+
+					snd_printddd("P%d write2 0x%04X 0x%04X\n",
 							s->number,
-							ds->period_bytes);
+							xfercount - xfer1, buf_ofs);
 					hpi_handle_error(
 						hpi_outstream_write_buf(
-							ds->h_stream,
-							&s->runtime->
-								dma_area[0],
-							xfercount,
+							ds->h_stream, pd,
+							xfercount - xfer1,
 							&ds->format));
-				} else {
-					snd_printddd("C%d read x%04x\n",
-						s->number,
-						xfercount);
+				}
+			} else {
+				snd_printddd("C%d read1 0x%04x\n",
+					s->number, xfer1);
+				hpi_handle_error(
+					hpi_instream_read_buf(
+						ds->h_stream,
+						pd, xfer1));
+				if (xfer2) {
+					pd = s->runtime->dma_area;
+					snd_printddd("C%d read2 0x%04x\n",
+						s->number, xfer2);
 					hpi_handle_error(
 						hpi_instream_read_buf(
 							ds->h_stream,
-							NULL, xfercount));
+							pd, xfer2));
 				}
-				ds->pcm_buf_host_rw_ofs = ds->pcm_buf_host_rw_ofs + xfercount;
-			} /* else R/W will be handled by read/write callbacks */
+			}
+			ds->pcm_buf_host_rw_ofs = ds->pcm_buf_host_rw_ofs + xfercount;
 			ds->pcm_buf_elapsed_dma_ofs = pcm_buf_dma_ofs;
 			snd_pcm_period_elapsed(s);
 		}
@@ -863,7 +917,7 @@ static void snd_card_asihpi_timer_function(unsigned long data)
 static int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream,
 					  unsigned int cmd, void *arg)
 {
-	snd_printdd(KERN_INFO "Playback ioctl %d\n", cmd);
+	snd_printddd(KERN_INFO "P%d ioctl %d\n", substream->number, cmd);
 	return snd_pcm_lib_ioctl(substream, cmd, arg);
 }
 
@@ -873,7 +927,7 @@ static int snd_card_asihpi_playback_prepare(struct snd_pcm_substream *
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
 
-	snd_printdd("playback prepare %d\n", substream->number);
+	snd_printdd("P%d prepare\n", substream->number);
 
 	hpi_handle_error(hpi_outstream_reset(dpcm->h_stream));
 	dpcm->pcm_buf_host_rw_ofs = 0;
@@ -890,7 +944,7 @@ snd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream)
 	snd_pcm_uframes_t ptr;
 
 	ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs  % dpcm->buffer_bytes);
-	snd_printddd("playback_pointer=x%04lx\n", (unsigned long)ptr);
+	snd_printddd("P%d pointer = 0x%04lx\n", substream->number, (unsigned long)ptr);
 	return ptr;
 }
 
@@ -986,11 +1040,9 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
 					SNDRV_PCM_INFO_DOUBLE |
 					SNDRV_PCM_INFO_BATCH |
 					SNDRV_PCM_INFO_BLOCK_TRANSFER |
-					SNDRV_PCM_INFO_PAUSE;
-
-	if (card->support_mmap)
-		snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_MMAP |
-						SNDRV_PCM_INFO_MMAP_VALID;
+					SNDRV_PCM_INFO_PAUSE |
+					SNDRV_PCM_INFO_MMAP |
+					SNDRV_PCM_INFO_MMAP_VALID;
 
 	if (card->support_grouping)
 		snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_SYNC_START;
@@ -998,7 +1050,7 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
 	/* struct is copied, so can create initializer dynamically */
 	runtime->hw = snd_card_asihpi_playback;
 
-	if (card->support_mmap)
+	if (card->can_dma)
 		err = snd_pcm_hw_constraint_pow2(runtime, 0,
 					SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
 	if (err < 0)
@@ -1028,58 +1080,6 @@ static int snd_card_asihpi_playback_close(struct snd_pcm_substream *substream)
 	return 0;
 }
 
-static int snd_card_asihpi_playback_copy(struct snd_pcm_substream *substream,
-					int channel,
-					snd_pcm_uframes_t pos,
-					void __user *src,
-					snd_pcm_uframes_t count)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
-	unsigned int len;
-
-	len = frames_to_bytes(runtime, count);
-
-	if (copy_from_user(runtime->dma_area, src, len))
-		return -EFAULT;
-
-	snd_printddd("playback copy%d %u bytes\n",
-			substream->number, len);
-
-	hpi_handle_error(hpi_outstream_write_buf(dpcm->h_stream,
-				runtime->dma_area, len, &dpcm->format));
-
-	dpcm->pcm_buf_host_rw_ofs += len;
-
-	return 0;
-}
-
-static int snd_card_asihpi_playback_silence(struct snd_pcm_substream *
-					    substream, int channel,
-					    snd_pcm_uframes_t pos,
-					    snd_pcm_uframes_t count)
-{
-	/* Usually writes silence to DMA buffer, which should be overwritten
-	by real audio later.  Our fifos cannot be overwritten, and are not
-	free-running DMAs. Silence is output on fifo underflow.
-	This callback is still required to allow the copy callback to be used.
-	*/
-	return 0;
-}
-
-static struct snd_pcm_ops snd_card_asihpi_playback_ops = {
-	.open = snd_card_asihpi_playback_open,
-	.close = snd_card_asihpi_playback_close,
-	.ioctl = snd_card_asihpi_playback_ioctl,
-	.hw_params = snd_card_asihpi_pcm_hw_params,
-	.hw_free = snd_card_asihpi_hw_free,
-	.prepare = snd_card_asihpi_playback_prepare,
-	.trigger = snd_card_asihpi_trigger,
-	.pointer = snd_card_asihpi_playback_pointer,
-	.copy = snd_card_asihpi_playback_copy,
-	.silence = snd_card_asihpi_playback_silence,
-};
-
 static struct snd_pcm_ops snd_card_asihpi_playback_mmap_ops = {
 	.open = snd_card_asihpi_playback_open,
 	.close = snd_card_asihpi_playback_close,
@@ -1211,18 +1211,16 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
 	snd_card_asihpi_capture_format(card, dpcm->h_stream,
 				       &snd_card_asihpi_capture);
 	snd_card_asihpi_pcm_samplerates(card,  &snd_card_asihpi_capture);
-	snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED;
-
-	if (card->support_mmap)
-		snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_MMAP |
-						SNDRV_PCM_INFO_MMAP_VALID;
+	snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED |
+					SNDRV_PCM_INFO_MMAP |
+					SNDRV_PCM_INFO_MMAP_VALID;
 
 	if (card->support_grouping)
 		snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_SYNC_START;
 
 	runtime->hw = snd_card_asihpi_capture;
 
-	if (card->support_mmap)
+	if (card->can_dma)
 		err = snd_pcm_hw_constraint_pow2(runtime, 0,
 					SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
 	if (err < 0)
@@ -1246,28 +1244,6 @@ static int snd_card_asihpi_capture_close(struct snd_pcm_substream *substream)
 	return 0;
 }
 
-static int snd_card_asihpi_capture_copy(struct snd_pcm_substream *substream,
-				int channel, snd_pcm_uframes_t pos,
-				void __user *dst, snd_pcm_uframes_t count)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
-	u32 len;
-
-	len = frames_to_bytes(runtime, count);
-
-	snd_printddd("capture copy%d %d bytes\n", substream->number, len);
-	hpi_handle_error(hpi_instream_read_buf(dpcm->h_stream,
-				runtime->dma_area, len));
-
-	dpcm->pcm_buf_host_rw_ofs = dpcm->pcm_buf_host_rw_ofs + len;
-
-	if (copy_to_user(dst, runtime->dma_area, len))
-		return -EFAULT;
-
-	return 0;
-}
-
 static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = {
 	.open = snd_card_asihpi_capture_open,
 	.close = snd_card_asihpi_capture_close,
@@ -1279,18 +1255,6 @@ static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = {
 	.pointer = snd_card_asihpi_capture_pointer,
 };
 
-static struct snd_pcm_ops snd_card_asihpi_capture_ops = {
-	.open = snd_card_asihpi_capture_open,
-	.close = snd_card_asihpi_capture_close,
-	.ioctl = snd_card_asihpi_capture_ioctl,
-	.hw_params = snd_card_asihpi_pcm_hw_params,
-	.hw_free = snd_card_asihpi_hw_free,
-	.prepare = snd_card_asihpi_capture_prepare,
-	.trigger = snd_card_asihpi_trigger,
-	.pointer = snd_card_asihpi_capture_pointer,
-	.copy = snd_card_asihpi_capture_copy
-};
-
 static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi,
 				      int device, int substreams)
 {
@@ -1303,17 +1267,10 @@ static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi,
 	if (err < 0)
 		return err;
 	/* pointer to ops struct is stored, dont change ops afterwards! */
-	if (asihpi->support_mmap) {
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
 				&snd_card_asihpi_playback_mmap_ops);
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
 				&snd_card_asihpi_capture_mmap_ops);
-	} else {
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-				&snd_card_asihpi_playback_ops);
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
-				&snd_card_asihpi_capture_ops);
-	}
 
 	pcm->private_data = asihpi;
 	pcm->info_flags = 0;
@@ -1413,14 +1370,16 @@ static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control,
 				struct hpi_control *hpi_ctl,
 				char *name)
 {
-	char *dir = "";
+	char *dir;
 	memset(snd_control, 0, sizeof(*snd_control));
 	snd_control->name = hpi_ctl->name;
 	snd_control->private_value = hpi_ctl->h_control;
 	snd_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 	snd_control->index = 0;
 
-	if (hpi_ctl->dst_node_type + HPI_DESTNODE_NONE == HPI_DESTNODE_ISTREAM)
+	if (hpi_ctl->src_node_type + HPI_SOURCENODE_NONE == HPI_SOURCENODE_CLOCK_SOURCE)
+		dir = ""; /* clock is neither capture nor playback */
+	else if (hpi_ctl->dst_node_type + HPI_DESTNODE_NONE == HPI_DESTNODE_ISTREAM)
 		dir = "Capture ";  /* On or towards a PCM capture destination*/
 	else if ((hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) &&
 		(!hpi_ctl->dst_node_type))
@@ -1433,7 +1392,7 @@ static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control,
 		dir = "Playback "; /* PCM Playback source, or  output node */
 
 	if (hpi_ctl->src_node_type && hpi_ctl->dst_node_type)
-		sprintf(hpi_ctl->name, "%s%d %s%d %s%s",
+		sprintf(hpi_ctl->name, "%s %d %s %d %s%s",
 			asihpi_src_names[hpi_ctl->src_node_type],
 			hpi_ctl->src_node_index,
 			asihpi_dst_names[hpi_ctl->dst_node_type],
@@ -2875,14 +2834,14 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
 	if (err)
 		asihpi->update_interval_frames = 512;
 
-	if (!asihpi->support_mmap)
+	if (!asihpi->can_dma)
 		asihpi->update_interval_frames *= 2;
 
 	hpi_handle_error(hpi_instream_open(asihpi->adapter_index,
 			     0, &h_stream));
 
 	err = hpi_instream_host_buffer_free(h_stream);
-	asihpi->support_mmap = (!err);
+	asihpi->can_dma = (!err);
 
 	hpi_handle_error(hpi_instream_close(h_stream));
 
@@ -2894,8 +2853,8 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
 		asihpi->out_max_chans = 2;
 	}
 
-	snd_printk(KERN_INFO "supports mmap:%d grouping:%d mrx:%d\n",
-			asihpi->support_mmap,
+	snd_printk(KERN_INFO "has dma:%d, grouping:%d, mrx:%d\n",
+			asihpi->can_dma,
 			asihpi->support_grouping,
 			asihpi->support_mrx
 	      );
@@ -2925,10 +2884,7 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
 	    by enable_hwdep  module param*/
 	snd_asihpi_hpi_new(asihpi, 0, NULL);
 
-	if (asihpi->support_mmap)
-		strcpy(card->driver, "ASIHPI-MMAP");
-	else
-		strcpy(card->driver, "ASIHPI");
+	strcpy(card->driver, "ASIHPI");
 
 	sprintf(card->shortname, "AudioScience ASI%4X", asihpi->type);
 	sprintf(card->longname, "%s %i",
diff --git a/sound/pci/asihpi/hpi6000.c b/sound/pci/asihpi/hpi6000.c
index 8c8aac4c567e..df4aed5295dd 100644
--- a/sound/pci/asihpi/hpi6000.c
+++ b/sound/pci/asihpi/hpi6000.c
@@ -200,8 +200,8 @@ static void hpi_read_block(struct dsp_obj *pdo, u32 address, u32 *pdata,
 static void subsys_create_adapter(struct hpi_message *phm,
 	struct hpi_response *phr);
 
-static void subsys_delete_adapter(struct hpi_message *phm,
-	struct hpi_response *phr);
+static void adapter_delete(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr);
 
 static void adapter_get_asserts(struct hpi_adapter_obj *pao,
 	struct hpi_message *phm, struct hpi_response *phr);
@@ -222,9 +222,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
 	case HPI_SUBSYS_CREATE_ADAPTER:
 		subsys_create_adapter(phm, phr);
 		break;
-	case HPI_SUBSYS_DELETE_ADAPTER:
-		subsys_delete_adapter(phm, phr);
-		break;
 	default:
 		phr->error = HPI_ERROR_INVALID_FUNC;
 		break;
@@ -279,6 +276,10 @@ static void adapter_message(struct hpi_adapter_obj *pao,
 		adapter_get_asserts(pao, phm, phr);
 		break;
 
+	case HPI_ADAPTER_DELETE:
+		adapter_delete(pao, phm, phr);
+		break;
+
 	default:
 		hw_message(pao, phm, phr);
 		break;
@@ -333,26 +334,22 @@ void HPI_6000(struct hpi_message *phm, struct hpi_response *phr)
 {
 	struct hpi_adapter_obj *pao = NULL;
 
-	/* subsytem messages get executed by every HPI. */
-	/* All other messages are ignored unless the adapter index matches */
-	/* an adapter in the HPI */
-	/*HPI_DEBUG_LOG(DEBUG, "O %d,F %x\n", phm->wObject, phm->wFunction); */
-
-	/* if Dsp has crashed then do not communicate with it any more */
 	if (phm->object != HPI_OBJ_SUBSYSTEM) {
 		pao = hpi_find_adapter(phm->adapter_index);
 		if (!pao) {
-			HPI_DEBUG_LOG(DEBUG,
-				" %d,%d refused, for another HPI?\n",
-				phm->object, phm->function);
+			hpi_init_response(phr, phm->object, phm->function,
+				HPI_ERROR_BAD_ADAPTER_NUMBER);
+			HPI_DEBUG_LOG(DEBUG, "invalid adapter index: %d \n",
+				phm->adapter_index);
 			return;
 		}
 
+		/* Don't even try to communicate with crashed DSP */
 		if (pao->dsp_crashed >= 10) {
 			hpi_init_response(phr, phm->object, phm->function,
 				HPI_ERROR_DSP_HARDWARE);
-			HPI_DEBUG_LOG(DEBUG, " %d,%d dsp crashed.\n",
-				phm->object, phm->function);
+			HPI_DEBUG_LOG(DEBUG, "adapter %d dsp crashed\n",
+				phm->adapter_index);
 			return;
 		}
 	}
@@ -463,15 +460,9 @@ static void subsys_create_adapter(struct hpi_message *phm,
 	phr->error = 0;
 }
 
-static void subsys_delete_adapter(struct hpi_message *phm,
-	struct hpi_response *phr)
+static void adapter_delete(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
 {
-	struct hpi_adapter_obj *pao = NULL;
-
-	pao = hpi_find_adapter(phm->obj_index);
-	if (!pao)
-		return;
-
 	delete_adapter_obj(pao);
 	hpi_delete_adapter(pao);
 	phr->error = 0;
diff --git a/sound/pci/asihpi/hpi6205.c b/sound/pci/asihpi/hpi6205.c
index 22e9f08dea6d..9d5df54a6b46 100644
--- a/sound/pci/asihpi/hpi6205.c
+++ b/sound/pci/asihpi/hpi6205.c
@@ -152,8 +152,8 @@ static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
 
 static void subsys_create_adapter(struct hpi_message *phm,
 	struct hpi_response *phr);
-static void subsys_delete_adapter(struct hpi_message *phm,
-	struct hpi_response *phr);
+static void adapter_delete(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr);
 
 static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
 	u32 *pos_error_code);
@@ -223,15 +223,13 @@ static u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index);
 
 /*****************************************************************************/
 
-static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
+static void subsys_message(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
 {
 	switch (phm->function) {
 	case HPI_SUBSYS_CREATE_ADAPTER:
 		subsys_create_adapter(phm, phr);
 		break;
-	case HPI_SUBSYS_DELETE_ADAPTER:
-		subsys_delete_adapter(phm, phr);
-		break;
 	default:
 		phr->error = HPI_ERROR_INVALID_FUNC;
 		break;
@@ -279,6 +277,10 @@ static void adapter_message(struct hpi_adapter_obj *pao,
 	struct hpi_message *phm, struct hpi_response *phr)
 {
 	switch (phm->function) {
+	case HPI_ADAPTER_DELETE:
+		adapter_delete(pao, phm, phr);
+		break;
+
 	default:
 		hw_message(pao, phm, phr);
 		break;
@@ -371,36 +373,17 @@ static void instream_message(struct hpi_adapter_obj *pao,
 /** Entry point to this HPI backend
  * All calls to the HPI start here
  */
-void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
+void _HPI_6205(struct hpi_adapter_obj *pao, struct hpi_message *phm,
+	struct hpi_response *phr)
 {
-	struct hpi_adapter_obj *pao = NULL;
-
-	/* subsytem messages are processed by every HPI.
-	 * All other messages are ignored unless the adapter index matches
-	 * an adapter in the HPI
-	 */
-	/* HPI_DEBUG_LOG(DEBUG, "HPI Obj=%d, Func=%d\n", phm->wObject,
-	   phm->wFunction); */
-
-	/* if Dsp has crashed then do not communicate with it any more */
-	if (phm->object != HPI_OBJ_SUBSYSTEM) {
-		pao = hpi_find_adapter(phm->adapter_index);
-		if (!pao) {
-			HPI_DEBUG_LOG(DEBUG,
-				" %d,%d refused, for another HPI?\n",
-				phm->object, phm->function);
-			return;
-		}
-
-		if ((pao->dsp_crashed >= 10)
-			&& (phm->function != HPI_ADAPTER_DEBUG_READ)) {
-			/* allow last resort debug read even after crash */
-			hpi_init_response(phr, phm->object, phm->function,
-				HPI_ERROR_DSP_HARDWARE);
-			HPI_DEBUG_LOG(WARNING, " %d,%d dsp crashed.\n",
-				phm->object, phm->function);
-			return;
-		}
+	if (pao && (pao->dsp_crashed >= 10)
+		&& (phm->function != HPI_ADAPTER_DEBUG_READ)) {
+		/* allow last resort debug read even after crash */
+		hpi_init_response(phr, phm->object, phm->function,
+			HPI_ERROR_DSP_HARDWARE);
+		HPI_DEBUG_LOG(WARNING, " %d,%d dsp crashed.\n", phm->object,
+			phm->function);
+		return;
 	}
 
 	/* Init default response  */
@@ -412,7 +395,7 @@ void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
 	case HPI_TYPE_MESSAGE:
 		switch (phm->object) {
 		case HPI_OBJ_SUBSYSTEM:
-			subsys_message(phm, phr);
+			subsys_message(pao, phm, phr);
 			break;
 
 		case HPI_OBJ_ADAPTER:
@@ -444,6 +427,26 @@ void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
 	}
 }
 
+void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
+{
+	struct hpi_adapter_obj *pao = NULL;
+
+	if (phm->object != HPI_OBJ_SUBSYSTEM) {
+		/* normal messages must have valid adapter index */
+		pao = hpi_find_adapter(phm->adapter_index);
+	} else {
+		/* subsys messages don't address an adapter */
+		_HPI_6205(NULL, phm, phr);
+		return;
+	}
+
+	if (pao)
+		_HPI_6205(pao, phm, phr);
+	else
+		hpi_init_response(phr, phm->object, phm->function,
+			HPI_ERROR_BAD_ADAPTER_NUMBER);
+}
+
 /*****************************************************************************/
 /* SUBSYSTEM */
 
@@ -491,13 +494,11 @@ static void subsys_create_adapter(struct hpi_message *phm,
 }
 
 /** delete an adapter - required by WDM driver */
-static void subsys_delete_adapter(struct hpi_message *phm,
-	struct hpi_response *phr)
+static void adapter_delete(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
 {
-	struct hpi_adapter_obj *pao;
 	struct hpi_hw_obj *phw;
 
-	pao = hpi_find_adapter(phm->obj_index);
 	if (!pao) {
 		phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
 		return;
@@ -563,11 +564,12 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
 	}
 
 	err = adapter_boot_load_dsp(pao, pos_error_code);
-	if (err)
+	if (err) {
+		HPI_DEBUG_LOG(ERROR, "DSP code load failed\n");
 		/* no need to clean up as SubSysCreateAdapter */
 		/* calls DeleteAdapter on error. */
 		return err;
-
+	}
 	HPI_DEBUG_LOG(INFO, "load DSP code OK\n");
 
 	/* allow boot load even if mem alloc wont work */
@@ -604,6 +606,7 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
 				control_cache.number_of_controls,
 				interface->control_cache.size_in_bytes,
 				p_control_cache_virtual);
+
 			if (!phw->p_cache)
 				err = HPI_ERROR_MEMORY_ALLOC;
 		}
@@ -675,16 +678,14 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
 }
 
 /** Free memory areas allocated by adapter
- * this routine is called from SubSysDeleteAdapter,
+ * this routine is called from AdapterDelete,
   * and SubSysCreateAdapter if duplicate index
 */
 static void delete_adapter_obj(struct hpi_adapter_obj *pao)
 {
-	struct hpi_hw_obj *phw;
+	struct hpi_hw_obj *phw = pao->priv;
 	int i;
 
-	phw = pao->priv;
-
 	if (hpios_locked_mem_valid(&phw->h_control_cache)) {
 		hpios_locked_mem_free(&phw->h_control_cache);
 		hpi_free_control_cache(phw->p_cache);
@@ -1275,6 +1276,7 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
 	case HPI_ADAPTER_FAMILY_ASI(0x6300):
 		boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6400);
 		break;
+	case HPI_ADAPTER_FAMILY_ASI(0x5500):
 	case HPI_ADAPTER_FAMILY_ASI(0x5600):
 	case HPI_ADAPTER_FAMILY_ASI(0x6500):
 		boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6600);
@@ -2059,7 +2061,6 @@ static int wait_dsp_ack(struct hpi_hw_obj *phw, int state, int timeout_us)
 static void send_dsp_command(struct hpi_hw_obj *phw, int cmd)
 {
 	struct bus_master_interface *interface = phw->p_interface_buffer;
-
 	u32 r;
 
 	interface->host_cmd = cmd;
diff --git a/sound/pci/asihpi/hpi_internal.h b/sound/pci/asihpi/hpi_internal.h
index 3b9fd115da36..bf5eced76bac 100644
--- a/sound/pci/asihpi/hpi_internal.h
+++ b/sound/pci/asihpi/hpi_internal.h
@@ -294,7 +294,7 @@ enum HPI_CONTROL_ATTRIBUTES {
 
 /* These defines are used to fill in protocol information for an Ethernet packet
     sent using HMI on CS18102 */
-/** ID supplied by Cirrius for ASI packets. */
+/** ID supplied by Cirrus for ASI packets. */
 #define HPI_ETHERNET_PACKET_ID                  0x85
 /** Simple packet - no special routing required */
 #define HPI_ETHERNET_PACKET_V1                  0x01
@@ -307,7 +307,7 @@ enum HPI_CONTROL_ATTRIBUTES {
 /** This packet must make its way to the host across the HPI interface */
 #define HPI_ETHERNET_PACKET_HOSTED_VIA_HPI_V1   0x41
 
-#define HPI_ETHERNET_UDP_PORT (44600)	/*!< UDP messaging port */
+#define HPI_ETHERNET_UDP_PORT 44600 /**< HPI UDP service */
 
 /** Default network timeout in milli-seconds. */
 #define HPI_ETHERNET_TIMEOUT_MS 500
@@ -397,14 +397,14 @@ enum HPI_FUNCTION_IDS {
 	HPI_SUBSYS_OPEN = HPI_FUNC_ID(SUBSYSTEM, 1),
 	HPI_SUBSYS_GET_VERSION = HPI_FUNC_ID(SUBSYSTEM, 2),
 	HPI_SUBSYS_GET_INFO = HPI_FUNC_ID(SUBSYSTEM, 3),
-	HPI_SUBSYS_FIND_ADAPTERS = HPI_FUNC_ID(SUBSYSTEM, 4),
+	/* HPI_SUBSYS_FIND_ADAPTERS     = HPI_FUNC_ID(SUBSYSTEM, 4), */
 	HPI_SUBSYS_CREATE_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 5),
 	HPI_SUBSYS_CLOSE = HPI_FUNC_ID(SUBSYSTEM, 6),
-	HPI_SUBSYS_DELETE_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 7),
+	/* HPI_SUBSYS_DELETE_ADAPTER    = HPI_FUNC_ID(SUBSYSTEM, 7), */
 	HPI_SUBSYS_DRIVER_LOAD = HPI_FUNC_ID(SUBSYSTEM, 8),
 	HPI_SUBSYS_DRIVER_UNLOAD = HPI_FUNC_ID(SUBSYSTEM, 9),
-	HPI_SUBSYS_READ_PORT_8 = HPI_FUNC_ID(SUBSYSTEM, 10),
-	HPI_SUBSYS_WRITE_PORT_8 = HPI_FUNC_ID(SUBSYSTEM, 11),
+	/* HPI_SUBSYS_READ_PORT_8               = HPI_FUNC_ID(SUBSYSTEM, 10), */
+	/* HPI_SUBSYS_WRITE_PORT_8              = HPI_FUNC_ID(SUBSYSTEM, 11), */
 	HPI_SUBSYS_GET_NUM_ADAPTERS = HPI_FUNC_ID(SUBSYSTEM, 12),
 	HPI_SUBSYS_GET_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 13),
 	HPI_SUBSYS_SET_NETWORK_INTERFACE = HPI_FUNC_ID(SUBSYSTEM, 14),
@@ -433,7 +433,8 @@ enum HPI_FUNCTION_IDS {
 	HPI_ADAPTER_DEBUG_READ = HPI_FUNC_ID(ADAPTER, 18),
 	HPI_ADAPTER_IRQ_QUERY_AND_CLEAR = HPI_FUNC_ID(ADAPTER, 19),
 	HPI_ADAPTER_IRQ_CALLBACK = HPI_FUNC_ID(ADAPTER, 20),
-#define HPI_ADAPTER_FUNCTION_COUNT 20
+	HPI_ADAPTER_DELETE = HPI_FUNC_ID(ADAPTER, 21),
+#define HPI_ADAPTER_FUNCTION_COUNT 21
 
 	HPI_OSTREAM_OPEN = HPI_FUNC_ID(OSTREAM, 1),
 	HPI_OSTREAM_CLOSE = HPI_FUNC_ID(OSTREAM, 2),
@@ -1561,8 +1562,6 @@ void hpi_send_recv(struct hpi_message *phm, struct hpi_response *phr);
 u16 hpi_subsys_create_adapter(const struct hpi_resource *p_resource,
 	u16 *pw_adapter_index);
 
-u16 hpi_subsys_delete_adapter(u16 adapter_index);
-
 u16 hpi_outstream_host_buffer_get_info(u32 h_outstream, u8 **pp_buffer,
 	struct hpi_hostbuffer_status **pp_status);
 
@@ -1584,9 +1583,7 @@ void hpi_stream_response_to_legacy(struct hpi_stream_res *pSR);
 
 /*////////////////////////////////////////////////////////////////////////// */
 /* declarations for individual HPI entry points */
-hpi_handler_func HPI_1000;
 hpi_handler_func HPI_6000;
 hpi_handler_func HPI_6205;
-hpi_handler_func HPI_COMMON;
 
 #endif				/* _HPI_INTERNAL_H_ */
diff --git a/sound/pci/asihpi/hpicmn.c b/sound/pci/asihpi/hpicmn.c
index 3e9c5c289764..b15a02e91f82 100644
--- a/sound/pci/asihpi/hpicmn.c
+++ b/sound/pci/asihpi/hpicmn.c
@@ -227,8 +227,9 @@ static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC)
 			if (info->control_type) {
 				pC->p_info[info->control_index] = info;
 				cached++;
-			} else	/* dummy cache entry */
+			} else {	/* dummy cache entry */
 				pC->p_info[info->control_index] = NULL;
+			}
 
 			byte_count += info->size_in32bit_words * 4;
 
@@ -298,7 +299,7 @@ struct pad_ofs_size {
 	unsigned int field_size;
 };
 
-static struct pad_ofs_size pad_desc[] = {
+static const struct pad_ofs_size pad_desc[] = {
 	HPICMN_PAD_OFS_AND_SIZE(c_channel),	/* HPI_PAD_CHANNEL_NAME */
 	HPICMN_PAD_OFS_AND_SIZE(c_artist),	/* HPI_PAD_ARTIST */
 	HPICMN_PAD_OFS_AND_SIZE(c_title),	/* HPI_PAD_TITLE */
@@ -617,6 +618,10 @@ void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache,
 	}
 }
 
+/** Allocate control cache.
+
+\return Cache pointer, or NULL if allocation fails.
+*/
 struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count,
 	const u32 size_in_bytes, u8 *p_dsp_control_buffer)
 {
@@ -667,7 +672,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
 		phr->u.s.num_adapters = adapters.gw_num_adapters;
 		break;
 	case HPI_SUBSYS_CREATE_ADAPTER:
-	case HPI_SUBSYS_DELETE_ADAPTER:
 		break;
 	default:
 		phr->error = HPI_ERROR_INVALID_FUNC;
diff --git a/sound/pci/asihpi/hpicmn.h b/sound/pci/asihpi/hpicmn.h
index 590f0b69e655..d53cdf6e535f 100644
--- a/sound/pci/asihpi/hpicmn.h
+++ b/sound/pci/asihpi/hpicmn.h
@@ -60,3 +60,5 @@ void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *pC,
 	struct hpi_message *phm, struct hpi_response *phr);
 
 u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr);
+
+hpi_handler_func HPI_COMMON;
diff --git a/sound/pci/asihpi/hpifunc.c b/sound/pci/asihpi/hpifunc.c
index c38fc9487560..7397b169b89f 100644
--- a/sound/pci/asihpi/hpifunc.c
+++ b/sound/pci/asihpi/hpifunc.c
@@ -105,33 +105,6 @@ u16 hpi_subsys_get_version_ex(u32 *pversion_ex)
 	return hr.error;
 }
 
-u16 hpi_subsys_create_adapter(const struct hpi_resource *p_resource,
-	u16 *pw_adapter_index)
-{
-	struct hpi_message hm;
-	struct hpi_response hr;
-
-	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
-		HPI_SUBSYS_CREATE_ADAPTER);
-	hm.u.s.resource = *p_resource;
-
-	hpi_send_recv(&hm, &hr);
-
-	*pw_adapter_index = hr.u.s.adapter_index;
-	return hr.error;
-}
-
-u16 hpi_subsys_delete_adapter(u16 adapter_index)
-{
-	struct hpi_message hm;
-	struct hpi_response hr;
-	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
-		HPI_SUBSYS_DELETE_ADAPTER);
-	hm.obj_index = adapter_index;
-	hpi_send_recv(&hm, &hr);
-	return hr.error;
-}
-
 u16 hpi_subsys_get_num_adapters(int *pn_num_adapters)
 {
 	struct hpi_message hm;
diff --git a/sound/pci/asihpi/hpimsgx.c b/sound/pci/asihpi/hpimsgx.c
index 360028b9abf5..7352a5f7b4f7 100644
--- a/sound/pci/asihpi/hpimsgx.c
+++ b/sound/pci/asihpi/hpimsgx.c
@@ -211,24 +211,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr,
 		HPIMSGX__init(phm, phr);
 		break;
 
-	case HPI_SUBSYS_DELETE_ADAPTER:
-		HPIMSGX__cleanup(phm->obj_index, h_owner);
-		{
-			struct hpi_message hm;
-			struct hpi_response hr;
-			hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
-				HPI_ADAPTER_CLOSE);
-			hm.adapter_index = phm->obj_index;
-			hw_entry_point(&hm, &hr);
-		}
-		if ((phm->obj_index < HPI_MAX_ADAPTERS)
-			&& hpi_entry_points[phm->obj_index]) {
-			hpi_entry_points[phm->obj_index] (phm, phr);
-			hpi_entry_points[phm->obj_index] = NULL;
-		} else
-			phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
-
-		break;
 	default:
 		/* Must explicitly handle every subsys message in this switch */
 		hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function,
@@ -247,6 +229,19 @@ static void adapter_message(struct hpi_message *phm, struct hpi_response *phr,
 	case HPI_ADAPTER_CLOSE:
 		adapter_close(phm, phr);
 		break;
+	case HPI_ADAPTER_DELETE:
+		HPIMSGX__cleanup(phm->adapter_index, h_owner);
+		{
+			struct hpi_message hm;
+			struct hpi_response hr;
+			hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+				HPI_ADAPTER_CLOSE);
+			hm.adapter_index = phm->adapter_index;
+			hw_entry_point(&hm, &hr);
+		}
+		hw_entry_point(phm, phr);
+		break;
+
 	default:
 		hw_entry_point(phm, phr);
 		break;
diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c
index cd624f13ff8e..d8e7047512f8 100644
--- a/sound/pci/asihpi/hpioctl.c
+++ b/sound/pci/asihpi/hpioctl.c
@@ -25,6 +25,7 @@ Common Linux HPI ioctl and module probe/remove functions
 #include "hpidebug.h"
 #include "hpimsgx.h"
 #include "hpioctl.h"
+#include "hpicmn.h"
 
 #include <linux/fs.h>
 #include <linux/slab.h>
@@ -161,26 +162,24 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 		goto out;
 	}
 
-	pa = &adapters[hm->h.adapter_index];
+	switch (hm->h.function) {
+	case HPI_SUBSYS_CREATE_ADAPTER:
+	case HPI_ADAPTER_DELETE:
+		/* Application must not use these functions! */
+		hr->h.size = sizeof(hr->h);
+		hr->h.error = HPI_ERROR_INVALID_OPERATION;
+		hr->h.function = hm->h.function;
+		uncopied_bytes = copy_to_user(puhr, hr, hr->h.size);
+		if (uncopied_bytes)
+			err = -EFAULT;
+		else
+			err = 0;
+		goto out;
+	}
+
 	hr->h.size = res_max_size;
 	if (hm->h.object == HPI_OBJ_SUBSYSTEM) {
-		switch (hm->h.function) {
-		case HPI_SUBSYS_CREATE_ADAPTER:
-		case HPI_SUBSYS_DELETE_ADAPTER:
-			/* Application must not use these functions! */
-			hr->h.size = sizeof(hr->h);
-			hr->h.error = HPI_ERROR_INVALID_OPERATION;
-			hr->h.function = hm->h.function;
-			uncopied_bytes = copy_to_user(puhr, hr, hr->h.size);
-			if (uncopied_bytes)
-				err = -EFAULT;
-			else
-				err = 0;
-			goto out;
-
-		default:
-			hpi_send_recv_f(&hm->m0, &hr->r0, file);
-		}
+		hpi_send_recv_f(&hm->m0, &hr->r0, file);
 	} else {
 		u16 __user *ptr = NULL;
 		u32 size = 0;
@@ -188,8 +187,9 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 		/* -1=no data 0=read from user mem, 1=write to user mem */
 		int wrflag = -1;
 		u32 adapter = hm->h.adapter_index;
+		pa = &adapters[adapter];
 
-		if ((hm->h.adapter_index > HPI_MAX_ADAPTERS) || (!pa->type)) {
+		if ((adapter > HPI_MAX_ADAPTERS) || (!pa->type)) {
 			hpi_init_response(&hr->r0, HPI_OBJ_ADAPTER,
 				HPI_ADAPTER_OPEN,
 				HPI_ERROR_BAD_ADAPTER_NUMBER);
@@ -317,7 +317,7 @@ out:
 int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
 	const struct pci_device_id *pci_id)
 {
-	int err, idx, nm;
+	int idx, nm;
 	unsigned int memlen;
 	struct hpi_message hm;
 	struct hpi_response hr;
@@ -351,11 +351,8 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
 	nm = HPI_MAX_ADAPTER_MEM_SPACES;
 
 	for (idx = 0; idx < nm; idx++) {
-		HPI_DEBUG_LOG(INFO, "resource %d %s %08llx-%08llx %04llx\n",
-			idx, pci_dev->resource[idx].name,
-			(unsigned long long)pci_resource_start(pci_dev, idx),
-			(unsigned long long)pci_resource_end(pci_dev, idx),
-			(unsigned long long)pci_resource_flags(pci_dev, idx));
+		HPI_DEBUG_LOG(INFO, "resource %d %pR\n", idx,
+			&pci_dev->resource[idx]);
 
 		if (pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM) {
 			memlen = pci_resource_len(pci_dev, idx);
@@ -395,17 +392,20 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
 
 	adapter.index = hr.u.s.adapter_index;
 	adapter.type = hr.u.s.adapter_type;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+		HPI_ADAPTER_OPEN);
 	hm.adapter_index = adapter.index;
+	hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
 
-	err = hpi_adapter_open(adapter.index);
-	if (err)
+	if (hr.error)
 		goto err;
 
 	adapter.snd_card_asihpi = NULL;
 	/* WARNING can't init mutex in 'adapter'
 	 * and then copy it to adapters[] ?!?!
 	 */
-	adapters[hr.u.s.adapter_index] = adapter;
+	adapters[adapter.index] = adapter;
 	mutex_init(&adapters[adapter.index].mutex);
 	pci_set_drvdata(pci_dev, &adapters[adapter.index]);
 
@@ -440,10 +440,9 @@ void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev)
 	struct hpi_adapter *pa;
 	pa = pci_get_drvdata(pci_dev);
 
-	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
-		HPI_SUBSYS_DELETE_ADAPTER);
-	hm.obj_index = pa->index;
-	hm.adapter_index = HPI_ADAPTER_INDEX_INVALID;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+		HPI_ADAPTER_DELETE);
+	hm.adapter_index = pa->index;
 	hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
 
 	/* unmap PCI memory space, mapped during device init. */
diff --git a/sound/pci/au88x0/au8810.h b/sound/pci/au88x0/au8810.h
index 5d69c31fe3f4..79fbee3845eb 100644
--- a/sound/pci/au88x0/au8810.h
+++ b/sound/pci/au88x0/au8810.h
@@ -4,7 +4,7 @@
 
 #define CHIP_AU8810
 
-#define CARD_NAME "Aureal Advantage 3D Sound Processor"
+#define CARD_NAME "Aureal Advantage"
 #define CARD_NAME_SHORT "au8810"
 
 #define NR_ADB		0x10
diff --git a/sound/pci/au88x0/au8820.h b/sound/pci/au88x0/au8820.h
index abbe85e4f7a9..cafdb9668a34 100644
--- a/sound/pci/au88x0/au8820.h
+++ b/sound/pci/au88x0/au8820.h
@@ -11,7 +11,7 @@
 
 #define CHIP_AU8820
 
-#define CARD_NAME "Aureal Vortex 3D Sound Processor"
+#define CARD_NAME "Aureal Vortex"
 #define CARD_NAME_SHORT "au8820"
 
 /* Number of ADB and WT channels */
diff --git a/sound/pci/au88x0/au8830.h b/sound/pci/au88x0/au8830.h
index 04ece1b1c218..999b29ab34ad 100644
--- a/sound/pci/au88x0/au8830.h
+++ b/sound/pci/au88x0/au8830.h
@@ -11,7 +11,7 @@
 
 #define CHIP_AU8830
 
-#define CARD_NAME "Aureal Vortex 2 3D Sound Processor"
+#define CARD_NAME "Aureal Vortex 2"
 #define CARD_NAME_SHORT "au8830"
 
 #define NR_ADB 0x20
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c
index 62e959120c44..c5f7ae46afef 100644
--- a/sound/pci/au88x0/au88x0_pcm.c
+++ b/sound/pci/au88x0/au88x0_pcm.c
@@ -426,11 +426,11 @@ static struct snd_pcm_ops snd_vortex_playback_ops = {
 */
 
 static char *vortex_pcm_prettyname[VORTEX_PCM_LAST] = {
-	"AU88x0 ADB",
-	"AU88x0 SPDIF",
-	"AU88x0 A3D",
-	"AU88x0 WT",
-	"AU88x0 I2S",
+	CARD_NAME " ADB",
+	CARD_NAME " SPDIF",
+	CARD_NAME " A3D",
+	CARD_NAME " WT",
+	CARD_NAME " I2S",
 };
 static char *vortex_pcm_name[VORTEX_PCM_LAST] = {
 	"adb",
@@ -527,7 +527,8 @@ static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr)
 			  nr_capt, &pcm);
 	if (err < 0)
 		return err;
-	strcpy(pcm->name, vortex_pcm_name[idx]);
+	snprintf(pcm->name, sizeof(pcm->name),
+		"%s %s", CARD_NAME_SHORT, vortex_pcm_name[idx]);
 	chip->pcm[idx] = pcm;
 	// This is an evil hack, but it saves a lot of duplicated code.
 	VORTEX_PCM_TYPE(pcm) = idx;
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index 7a9401462c1c..dae4050ede5c 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -303,6 +303,9 @@ static const u32 db_table[101] = {
 static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
 static const DECLARE_TLV_DB_LINEAR(snd_emu10k1_db_linear, TLV_DB_GAIN_MUTE, 0);
 
+/* EMU10K1 bass/treble db gain */
+static const DECLARE_TLV_DB_SCALE(snd_emu10k1_bass_treble_db_scale, -1200, 60, 0);
+
 static const u32 onoff_table[2] = {
 	0x00000000, 0x00000001
 };
@@ -2163,6 +2166,7 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
 	ctl->min = 0;
 	ctl->max = 40;
 	ctl->value[0] = ctl->value[1] = 20;
+	ctl->tlv = snd_emu10k1_bass_treble_db_scale;
 	ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
 	ctl = &controls[i + 1];
 	ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
@@ -2172,6 +2176,7 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
 	ctl->min = 0;
 	ctl->max = 40;
 	ctl->value[0] = ctl->value[1] = 20;
+	ctl->tlv = snd_emu10k1_bass_treble_db_scale;
 	ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
 
 #define BASS_GPR	0x8c
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
index 05afe06e353a..9d890a5aec5a 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -1729,8 +1729,6 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
 		"Master Mono Playback Volume",
 		"PCM Out Path & Mute",
 		"Mono Output Select",
-		"Front Playback Switch",
-		"Front Playback Volume",
 		"Surround Playback Switch",
 		"Surround Playback Volume",
 		"Center Playback Switch",
@@ -1879,6 +1877,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
 				emu->rear_ac97 = 1;
 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
 				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
+				remove_ctl(card,"Front Playback Volume");
+				remove_ctl(card,"Front Playback Switch");
 			}
 			/* remove unused AC97 controls */
 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
@@ -1913,6 +1913,12 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
 	for (; *c; c += 2)
 		rename_ctl(card, c[0], c[1]);
 
+	if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */
+		remove_ctl(card, "Center Playback Volume");
+		remove_ctl(card, "LFE Playback Volume");
+		remove_ctl(card, "Wave Center Playback Volume");
+		remove_ctl(card, "Wave LFE Playback Volume");
+	}
 	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
 		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
 		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index 7c17f45d876d..ab0a6156a704 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -112,6 +112,10 @@
 #include <sound/ac97_codec.h>
 #include <sound/initval.h>
 
+#ifdef CONFIG_SND_ES1968_RADIO
+#include <sound/tea575x-tuner.h>
+#endif
+
 #define CARD_NAME "ESS Maestro1/2"
 #define DRIVER_NAME "ES1968"
 
@@ -553,6 +557,10 @@ struct es1968 {
 	spinlock_t ac97_lock;
 	struct tasklet_struct hwvol_tq;
 #endif
+
+#ifdef CONFIG_SND_ES1968_RADIO
+	struct snd_tea575x tea;
+#endif
 };
 
 static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id);
@@ -2571,6 +2579,63 @@ static int __devinit snd_es1968_input_register(struct es1968 *chip)
 }
 #endif /* CONFIG_SND_ES1968_INPUT */
 
+#ifdef CONFIG_SND_ES1968_RADIO
+#define GPIO_DATA	0x60
+#define IO_MASK		4      /* mask      register offset from GPIO_DATA
+				bits 1=unmask write to given bit */
+#define IO_DIR		8      /* direction register offset from GPIO_DATA
+				bits 0/1=read/write direction */
+/* mask bits for GPIO lines */
+#define STR_DATA	0x0040 /* GPIO6 */
+#define STR_CLK		0x0080 /* GPIO7 */
+#define STR_WREN	0x0100 /* GPIO8 */
+#define STR_MOST	0x0200 /* GPIO9 */
+
+static void snd_es1968_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
+{
+	struct es1968 *chip = tea->private_data;
+	unsigned long io = chip->io_port + GPIO_DATA;
+	u16 val = 0;
+
+	val |= (pins & TEA575X_DATA) ? STR_DATA : 0;
+	val |= (pins & TEA575X_CLK)  ? STR_CLK  : 0;
+	val |= (pins & TEA575X_WREN) ? STR_WREN : 0;
+
+	outw(val, io);
+}
+
+static u8 snd_es1968_tea575x_get_pins(struct snd_tea575x *tea)
+{
+	struct es1968 *chip = tea->private_data;
+	unsigned long io = chip->io_port + GPIO_DATA;
+	u16 val = inw(io);
+
+	return  (val & STR_DATA) ? TEA575X_DATA : 0 |
+		(val & STR_MOST) ? TEA575X_MOST : 0;
+}
+
+static void snd_es1968_tea575x_set_direction(struct snd_tea575x *tea, bool output)
+{
+	struct es1968 *chip = tea->private_data;
+	unsigned long io = chip->io_port + GPIO_DATA;
+	u16 odir = inw(io + IO_DIR);
+
+	if (output) {
+		outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK);
+		outw(odir | STR_DATA | STR_CLK | STR_WREN, io + IO_DIR);
+	} else {
+		outw(~(STR_CLK | STR_WREN | STR_DATA | STR_MOST), io + IO_MASK);
+		outw((odir & ~(STR_DATA | STR_MOST)) | STR_CLK | STR_WREN, io + IO_DIR);
+	}
+}
+
+static struct snd_tea575x_ops snd_es1968_tea_ops = {
+	.set_pins = snd_es1968_tea575x_set_pins,
+	.get_pins = snd_es1968_tea575x_get_pins,
+	.set_direction = snd_es1968_tea575x_set_direction,
+};
+#endif
+
 static int snd_es1968_free(struct es1968 *chip)
 {
 #ifdef CONFIG_SND_ES1968_INPUT
@@ -2585,6 +2650,10 @@ static int snd_es1968_free(struct es1968 *chip)
 		outw(0, chip->io_port + ESM_PORT_HOST_IRQ); /* disable IRQ */
 	}
 
+#ifdef CONFIG_SND_ES1968_RADIO
+	snd_tea575x_exit(&chip->tea);
+#endif
+
 	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
 	snd_es1968_free_gameport(chip);
@@ -2723,6 +2792,15 @@ static int __devinit snd_es1968_create(struct snd_card *card,
 
 	snd_card_set_dev(card, &pci->dev);
 
+#ifdef CONFIG_SND_ES1968_RADIO
+	chip->tea.private_data = chip;
+	chip->tea.ops = &snd_es1968_tea_ops;
+	strlcpy(chip->tea.card, "SF64-PCE2", sizeof(chip->tea.card));
+	sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
+	if (!snd_tea575x_init(&chip->tea))
+		printk(KERN_INFO "es1968: detected TEA575x radio\n");
+#endif
+
 	*chip_ret = chip;
 
 	return 0;
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index e1baad74ea4b..eacd4901a308 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -38,7 +38,6 @@
 
 #ifdef CONFIG_SND_FM801_TEA575X_BOOL
 #include <sound/tea575x-tuner.h>
-#define TEA575X_RADIO 1
 #endif
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
@@ -53,7 +52,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card *
 /*
  *  Enable TEA575x tuner
  *    1 = MediaForte 256-PCS
- *    2 = MediaForte 256-PCPR
+ *    2 = MediaForte 256-PCP
  *    3 = MediaForte 64-PCR
  *   16 = setup tuner only (this is additional bit), i.e. SF64-PCR FM card
  *  High 16-bits are video (radio) device number + 1
@@ -67,7 +66,7 @@ MODULE_PARM_DESC(id, "ID string for the FM801 soundcard.");
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable FM801 soundcard.");
 module_param_array(tea575x_tuner, int, NULL, 0444);
-MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (1 = SF256-PCS, 2=SF256-PCPR, 3=SF64-PCR, +16=tuner-only).");
+MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (0 = auto, 1 = SF256-PCS, 2=SF256-PCP, 3=SF64-PCR, 8=disable, +16=tuner-only).");
 
 #define TUNER_ONLY		(1<<4)
 #define TUNER_TYPE_MASK		(~TUNER_ONLY & 0xFFFF)
@@ -196,7 +195,7 @@ struct fm801 {
 	spinlock_t reg_lock;
 	struct snd_info_entry *proc_entry;
 
-#ifdef TEA575X_RADIO
+#ifdef CONFIG_SND_FM801_TEA575X_BOOL
 	struct snd_tea575x tea;
 #endif
 
@@ -715,310 +714,89 @@ static int __devinit snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pc
  *  TEA5757 radio
  */
 
-#ifdef TEA575X_RADIO
-
-/* 256PCS GPIO numbers */
-#define TEA_256PCS_DATA			1
-#define TEA_256PCS_WRITE_ENABLE		2	/* inverted */
-#define TEA_256PCS_BUS_CLOCK		3
-
-static void snd_fm801_tea575x_256pcs_write(struct snd_tea575x *tea, unsigned int val)
-{
-	struct fm801 *chip = tea->private_data;
-	unsigned short reg;
-	int i = 25;
+#ifdef CONFIG_SND_FM801_TEA575X_BOOL
 
-	spin_lock_irq(&chip->reg_lock);
-	reg = inw(FM801_REG(chip, GPIO_CTRL));
-	/* use GPIO lines and set write enable bit */
-	reg |= FM801_GPIO_GS(TEA_256PCS_DATA) |
-	       FM801_GPIO_GS(TEA_256PCS_WRITE_ENABLE) |
-	       FM801_GPIO_GS(TEA_256PCS_BUS_CLOCK);
-	/* all of lines are in the write direction */
-	/* clear data and clock lines */
-	reg &= ~(FM801_GPIO_GD(TEA_256PCS_DATA) |
-	         FM801_GPIO_GD(TEA_256PCS_WRITE_ENABLE) |
-	         FM801_GPIO_GD(TEA_256PCS_BUS_CLOCK) |
-	         FM801_GPIO_GP(TEA_256PCS_DATA) |
-	         FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK) |
-		 FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE));
-	outw(reg, FM801_REG(chip, GPIO_CTRL));
-	udelay(1);
-
-	while (i--) {
-		if (val & (1 << i))
-			reg |= FM801_GPIO_GP(TEA_256PCS_DATA);
-		else
-			reg &= ~FM801_GPIO_GP(TEA_256PCS_DATA);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-		reg |= FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		reg &= ~FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-	}
+/* GPIO to TEA575x maps */
+struct snd_fm801_tea575x_gpio {
+	u8 data, clk, wren, most;
+	char *name;
+};
 
-	/* and reset the write enable bit */
-	reg |= FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE) |
-	       FM801_GPIO_GP(TEA_256PCS_DATA);
-	outw(reg, FM801_REG(chip, GPIO_CTRL));
-	spin_unlock_irq(&chip->reg_lock);
-}
+static struct snd_fm801_tea575x_gpio snd_fm801_tea575x_gpios[] = {
+	{ .data = 1, .clk = 3, .wren = 2, .most = 0, .name = "SF256-PCS" },
+	{ .data = 1, .clk = 0, .wren = 2, .most = 3, .name = "SF256-PCP" },
+	{ .data = 2, .clk = 0, .wren = 1, .most = 3, .name = "SF64-PCR" },
+};
 
-static unsigned int snd_fm801_tea575x_256pcs_read(struct snd_tea575x *tea)
+static void snd_fm801_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
 {
 	struct fm801 *chip = tea->private_data;
-	unsigned short reg;
-	unsigned int val = 0;
-	int i;
-	
-	spin_lock_irq(&chip->reg_lock);
-	reg = inw(FM801_REG(chip, GPIO_CTRL));
-	/* use GPIO lines, set data direction to input */
-	reg |= FM801_GPIO_GS(TEA_256PCS_DATA) |
-	       FM801_GPIO_GS(TEA_256PCS_WRITE_ENABLE) |
-	       FM801_GPIO_GS(TEA_256PCS_BUS_CLOCK) |
-	       FM801_GPIO_GD(TEA_256PCS_DATA) |
-	       FM801_GPIO_GP(TEA_256PCS_DATA) |
-	       FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE);
-	/* all of lines are in the write direction, except data */
-	/* clear data, write enable and clock lines */
-	reg &= ~(FM801_GPIO_GD(TEA_256PCS_WRITE_ENABLE) |
-	         FM801_GPIO_GD(TEA_256PCS_BUS_CLOCK) |
-	         FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK));
-
-	for (i = 0; i < 24; i++) {
-		reg &= ~FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-		reg |= FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-		val <<= 1;
-		if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_256PCS_DATA))
-			val |= 1;
-	}
+	unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
+	struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1];
 
-	spin_unlock_irq(&chip->reg_lock);
+	reg &= ~(FM801_GPIO_GP(gpio.data) |
+		 FM801_GPIO_GP(gpio.clk) |
+		 FM801_GPIO_GP(gpio.wren));
 
-	return val;
-}
+	reg |= (pins & TEA575X_DATA) ? FM801_GPIO_GP(gpio.data) : 0;
+	reg |= (pins & TEA575X_CLK)  ? FM801_GPIO_GP(gpio.clk) : 0;
+	/* WRITE_ENABLE is inverted */
+	reg |= (pins & TEA575X_WREN) ? 0 : FM801_GPIO_GP(gpio.wren);
 
-/* 256PCPR GPIO numbers */
-#define TEA_256PCPR_BUS_CLOCK		0
-#define TEA_256PCPR_DATA		1
-#define TEA_256PCPR_WRITE_ENABLE	2	/* inverted */
-
-static void snd_fm801_tea575x_256pcpr_write(struct snd_tea575x *tea, unsigned int val)
-{
-	struct fm801 *chip = tea->private_data;
-	unsigned short reg;
-	int i = 25;
-
-	spin_lock_irq(&chip->reg_lock);
-	reg = inw(FM801_REG(chip, GPIO_CTRL));
-	/* use GPIO lines and set write enable bit */
-	reg |= FM801_GPIO_GS(TEA_256PCPR_DATA) |
-	       FM801_GPIO_GS(TEA_256PCPR_WRITE_ENABLE) |
-	       FM801_GPIO_GS(TEA_256PCPR_BUS_CLOCK);
-	/* all of lines are in the write direction */
-	/* clear data and clock lines */
-	reg &= ~(FM801_GPIO_GD(TEA_256PCPR_DATA) |
-	         FM801_GPIO_GD(TEA_256PCPR_WRITE_ENABLE) |
-	         FM801_GPIO_GD(TEA_256PCPR_BUS_CLOCK) |
-	         FM801_GPIO_GP(TEA_256PCPR_DATA) |
-	         FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK) |
-		 FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE));
 	outw(reg, FM801_REG(chip, GPIO_CTRL));
-	udelay(1);
-
-	while (i--) {
-		if (val & (1 << i))
-			reg |= FM801_GPIO_GP(TEA_256PCPR_DATA);
-		else
-			reg &= ~FM801_GPIO_GP(TEA_256PCPR_DATA);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-		reg |= FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		reg &= ~FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-	}
-
-	/* and reset the write enable bit */
-	reg |= FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE) |
-	       FM801_GPIO_GP(TEA_256PCPR_DATA);
-	outw(reg, FM801_REG(chip, GPIO_CTRL));
-	spin_unlock_irq(&chip->reg_lock);
 }
 
-static unsigned int snd_fm801_tea575x_256pcpr_read(struct snd_tea575x *tea)
+static u8 snd_fm801_tea575x_get_pins(struct snd_tea575x *tea)
 {
 	struct fm801 *chip = tea->private_data;
-	unsigned short reg;
-	unsigned int val = 0;
-	int i;
-	
-	spin_lock_irq(&chip->reg_lock);
-	reg = inw(FM801_REG(chip, GPIO_CTRL));
-	/* use GPIO lines, set data direction to input */
-	reg |= FM801_GPIO_GS(TEA_256PCPR_DATA) |
-	       FM801_GPIO_GS(TEA_256PCPR_WRITE_ENABLE) |
-	       FM801_GPIO_GS(TEA_256PCPR_BUS_CLOCK) |
-	       FM801_GPIO_GD(TEA_256PCPR_DATA) |
-	       FM801_GPIO_GP(TEA_256PCPR_DATA) |
-	       FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE);
-	/* all of lines are in the write direction, except data */
-	/* clear data, write enable and clock lines */
-	reg &= ~(FM801_GPIO_GD(TEA_256PCPR_WRITE_ENABLE) |
-	         FM801_GPIO_GD(TEA_256PCPR_BUS_CLOCK) |
-	         FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK));
-
-	for (i = 0; i < 24; i++) {
-		reg &= ~FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-		reg |= FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-		val <<= 1;
-		if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_256PCPR_DATA))
-			val |= 1;
-	}
+	unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
+	struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1];
 
-	spin_unlock_irq(&chip->reg_lock);
-
-	return val;
+	return  (reg & FM801_GPIO_GP(gpio.data)) ? TEA575X_DATA : 0 |
+		(reg & FM801_GPIO_GP(gpio.most)) ? TEA575X_MOST : 0;
 }
 
-/* 64PCR GPIO numbers */
-#define TEA_64PCR_BUS_CLOCK		0
-#define TEA_64PCR_WRITE_ENABLE		1	/* inverted */
-#define TEA_64PCR_DATA			2
-
-static void snd_fm801_tea575x_64pcr_write(struct snd_tea575x *tea, unsigned int val)
+static void snd_fm801_tea575x_set_direction(struct snd_tea575x *tea, bool output)
 {
 	struct fm801 *chip = tea->private_data;
-	unsigned short reg;
-	int i = 25;
+	unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
+	struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1];
 
-	spin_lock_irq(&chip->reg_lock);
-	reg = inw(FM801_REG(chip, GPIO_CTRL));
 	/* use GPIO lines and set write enable bit */
-	reg |= FM801_GPIO_GS(TEA_64PCR_DATA) |
-	       FM801_GPIO_GS(TEA_64PCR_WRITE_ENABLE) |
-	       FM801_GPIO_GS(TEA_64PCR_BUS_CLOCK);
-	/* all of lines are in the write direction */
-	/* clear data and clock lines */
-	reg &= ~(FM801_GPIO_GD(TEA_64PCR_DATA) |
-	         FM801_GPIO_GD(TEA_64PCR_WRITE_ENABLE) |
-	         FM801_GPIO_GD(TEA_64PCR_BUS_CLOCK) |
-	         FM801_GPIO_GP(TEA_64PCR_DATA) |
-	         FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK) |
-		 FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE));
-	outw(reg, FM801_REG(chip, GPIO_CTRL));
-	udelay(1);
-
-	while (i--) {
-		if (val & (1 << i))
-			reg |= FM801_GPIO_GP(TEA_64PCR_DATA);
-		else
-			reg &= ~FM801_GPIO_GP(TEA_64PCR_DATA);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-		reg |= FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		reg &= ~FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
+	reg |= FM801_GPIO_GS(gpio.data) |
+	       FM801_GPIO_GS(gpio.wren) |
+	       FM801_GPIO_GS(gpio.clk) |
+	       FM801_GPIO_GS(gpio.most);
+	if (output) {
+		/* all of lines are in the write direction */
+		/* clear data and clock lines */
+		reg &= ~(FM801_GPIO_GD(gpio.data) |
+			 FM801_GPIO_GD(gpio.wren) |
+			 FM801_GPIO_GD(gpio.clk) |
+			 FM801_GPIO_GP(gpio.data) |
+			 FM801_GPIO_GP(gpio.clk) |
+			 FM801_GPIO_GP(gpio.wren));
+	} else {
+		/* use GPIO lines, set data direction to input */
+		reg |= FM801_GPIO_GD(gpio.data) |
+		       FM801_GPIO_GD(gpio.most) |
+		       FM801_GPIO_GP(gpio.data) |
+		       FM801_GPIO_GP(gpio.most) |
+		       FM801_GPIO_GP(gpio.wren);
+		/* all of lines are in the write direction, except data */
+		/* clear data, write enable and clock lines */
+		reg &= ~(FM801_GPIO_GD(gpio.wren) |
+			 FM801_GPIO_GD(gpio.clk) |
+			 FM801_GPIO_GP(gpio.clk));
 	}
 
-	/* and reset the write enable bit */
-	reg |= FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE) |
-	       FM801_GPIO_GP(TEA_64PCR_DATA);
 	outw(reg, FM801_REG(chip, GPIO_CTRL));
-	spin_unlock_irq(&chip->reg_lock);
-}
-
-static unsigned int snd_fm801_tea575x_64pcr_read(struct snd_tea575x *tea)
-{
-	struct fm801 *chip = tea->private_data;
-	unsigned short reg;
-	unsigned int val = 0;
-	int i;
-	
-	spin_lock_irq(&chip->reg_lock);
-	reg = inw(FM801_REG(chip, GPIO_CTRL));
-	/* use GPIO lines, set data direction to input */
-	reg |= FM801_GPIO_GS(TEA_64PCR_DATA) |
-	       FM801_GPIO_GS(TEA_64PCR_WRITE_ENABLE) |
-	       FM801_GPIO_GS(TEA_64PCR_BUS_CLOCK) |
-	       FM801_GPIO_GD(TEA_64PCR_DATA) |
-	       FM801_GPIO_GP(TEA_64PCR_DATA) |
-	       FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE);
-	/* all of lines are in the write direction, except data */
-	/* clear data, write enable and clock lines */
-	reg &= ~(FM801_GPIO_GD(TEA_64PCR_WRITE_ENABLE) |
-	         FM801_GPIO_GD(TEA_64PCR_BUS_CLOCK) |
-	         FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK));
-
-	for (i = 0; i < 24; i++) {
-		reg &= ~FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-		reg |= FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-		val <<= 1;
-		if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_64PCR_DATA))
-			val |= 1;
-	}
-
-	spin_unlock_irq(&chip->reg_lock);
-
-	return val;
 }
 
-static void snd_fm801_tea575x_64pcr_mute(struct snd_tea575x *tea,
-					  unsigned int mute)
-{
-	struct fm801 *chip = tea->private_data;
-	unsigned short reg;
-
-	spin_lock_irq(&chip->reg_lock);
-
-	reg = inw(FM801_REG(chip, GPIO_CTRL));
-	if (mute)
-		/* 0xf800 (mute) */
-		reg &= ~FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE);
-	else
-		/* 0xf802 (unmute) */
-		reg |= FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE);
-	outw(reg, FM801_REG(chip, GPIO_CTRL));
-	udelay(1);
-
-	spin_unlock_irq(&chip->reg_lock);
-}
-
-static struct snd_tea575x_ops snd_fm801_tea_ops[3] = {
-	{
-		/* 1 = MediaForte 256-PCS */
-		.write = snd_fm801_tea575x_256pcs_write,
-		.read = snd_fm801_tea575x_256pcs_read,
-	},
-	{
-		/* 2 = MediaForte 256-PCPR */
-		.write = snd_fm801_tea575x_256pcpr_write,
-		.read = snd_fm801_tea575x_256pcpr_read,
-	},
-	{
-		/* 3 = MediaForte 64-PCR */
-		.write = snd_fm801_tea575x_64pcr_write,
-		.read = snd_fm801_tea575x_64pcr_read,
-		.mute = snd_fm801_tea575x_64pcr_mute,
-	}
+static struct snd_tea575x_ops snd_fm801_tea_ops = {
+	.set_pins = snd_fm801_tea575x_set_pins,
+	.get_pins = snd_fm801_tea575x_get_pins,
+	.set_direction = snd_fm801_tea575x_set_direction,
 };
 #endif
 
@@ -1371,7 +1149,7 @@ static int snd_fm801_free(struct fm801 *chip)
 	outw(cmdw, FM801_REG(chip, IRQ_MASK));
 
       __end_hw:
-#ifdef TEA575X_RADIO
+#ifdef CONFIG_SND_FM801_TEA575X_BOOL
 	snd_tea575x_exit(&chip->tea);
 #endif
 	if (chip->irq >= 0)
@@ -1450,16 +1228,25 @@ static int __devinit snd_fm801_create(struct snd_card *card,
 
 	snd_card_set_dev(card, &pci->dev);
 
-#ifdef TEA575X_RADIO
+#ifdef CONFIG_SND_FM801_TEA575X_BOOL
+	chip->tea.private_data = chip;
+	chip->tea.ops = &snd_fm801_tea_ops;
+	sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
 	if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 &&
 	    (tea575x_tuner & TUNER_TYPE_MASK) < 4) {
-		chip->tea.dev_nr = tea575x_tuner >> 16;
-		chip->tea.card = card;
-		chip->tea.freq_fixup = 10700;
-		chip->tea.private_data = chip;
-		chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & TUNER_TYPE_MASK) - 1];
-		snd_tea575x_init(&chip->tea);
-	}
+		if (snd_tea575x_init(&chip->tea))
+			snd_printk(KERN_ERR "TEA575x radio not found\n");
+	} else if ((tea575x_tuner & TUNER_TYPE_MASK) == 0)
+		/* autodetect tuner connection */
+		for (tea575x_tuner = 1; tea575x_tuner <= 3; tea575x_tuner++) {
+			chip->tea575x_tuner = tea575x_tuner;
+			if (!snd_tea575x_init(&chip->tea)) {
+				snd_printk(KERN_INFO "detected TEA575x radio type %s\n",
+					snd_fm801_tea575x_gpios[tea575x_tuner - 1].name);
+				break;
+			}
+		}
+	strlcpy(chip->tea.card, snd_fm801_tea575x_gpios[(tea575x_tuner & TUNER_TYPE_MASK) - 1].name, sizeof(chip->tea.card));
 #endif
 
 	*rchip = chip;
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 759ade12e758..8edd998509f7 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -307,6 +307,12 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
 }
 EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes);
 
+static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
+				hda_nid_t *conn_list, int max_conns);
+static bool add_conn_list(struct snd_array *array, hda_nid_t nid);
+static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst,
+			  hda_nid_t *src, int len);
+
 /**
  * snd_hda_get_connections - get connection list
  * @codec: the HDA codec
@@ -320,7 +326,44 @@ EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes);
  * Returns the number of connections, or a negative error code.
  */
 int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
-			    hda_nid_t *conn_list, int max_conns)
+			     hda_nid_t *conn_list, int max_conns)
+{
+	struct snd_array *array = &codec->conn_lists;
+	int i, len, old_used;
+	hda_nid_t list[HDA_MAX_CONNECTIONS];
+
+	/* look up the cached results */
+	for (i = 0; i < array->used; ) {
+		hda_nid_t *p = snd_array_elem(array, i);
+		len = p[1];
+		if (nid == *p)
+			return copy_conn_list(nid, conn_list, max_conns,
+					      p + 2, len);
+		i += len + 2;
+	}
+
+	len = _hda_get_connections(codec, nid, list, HDA_MAX_CONNECTIONS);
+	if (len < 0)
+		return len;
+
+	/* add to the cache */
+	old_used = array->used;
+	if (!add_conn_list(array, nid) || !add_conn_list(array, len))
+		goto error_add;
+	for (i = 0; i < len; i++)
+		if (!add_conn_list(array, list[i]))
+			goto error_add;
+
+	return copy_conn_list(nid, conn_list, max_conns, list, len);
+		
+ error_add:
+	array->used = old_used;
+	return -ENOMEM;
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_connections);
+
+static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
+			     hda_nid_t *conn_list, int max_conns)
 {
 	unsigned int parm;
 	int i, conn_len, conns;
@@ -417,8 +460,28 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
 	}
 	return conns;
 }
-EXPORT_SYMBOL_HDA(snd_hda_get_connections);
 
+static bool add_conn_list(struct snd_array *array, hda_nid_t nid)
+{
+	hda_nid_t *p = snd_array_new(array);
+	if (!p)
+		return false;
+	*p = nid;
+	return true;
+}
+
+static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst,
+			  hda_nid_t *src, int len)
+{
+	if (len > max_dst) {
+		snd_printk(KERN_ERR "hda_codec: "
+			   "Too many connections %d for NID 0x%x\n",
+			   len, nid);
+		return -EINVAL;
+	}
+	memcpy(dst, src, len * sizeof(hda_nid_t));
+	return len;
+}
 
 /**
  * snd_hda_queue_unsol_event - add an unsolicited event to queue
@@ -1019,6 +1082,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
 	list_del(&codec->list);
 	snd_array_free(&codec->mixers);
 	snd_array_free(&codec->nids);
+	snd_array_free(&codec->conn_lists);
 	codec->bus->caddr_tbl[codec->addr] = NULL;
 	if (codec->patch_ops.free)
 		codec->patch_ops.free(codec);
@@ -1079,6 +1143,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
 	snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
 	snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
 	snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8);
+	snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64);
 	if (codec->bus->modelname) {
 		codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
 		if (!codec->modelname) {
@@ -2556,7 +2621,7 @@ static unsigned int convert_to_spdif_status(unsigned short val)
 static void set_dig_out(struct hda_codec *codec, hda_nid_t nid,
 			int verb, int val)
 {
-	hda_nid_t *d;
+	const hda_nid_t *d;
 
 	snd_hda_codec_write_cache(codec, nid, 0, verb, val);
 	d = codec->slave_dig_outs;
@@ -3807,7 +3872,8 @@ EXPORT_SYMBOL_HDA(snd_hda_check_board_codec_sid_config);
  *
  * Returns 0 if successful, or a negative error code.
  */
-int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
+int snd_hda_add_new_ctls(struct hda_codec *codec,
+			 const struct snd_kcontrol_new *knew)
 {
 	int err;
 
@@ -3950,7 +4016,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
 				 struct hda_loopback_check *check,
 				 hda_nid_t nid)
 {
-	struct hda_amp_list *p;
+	const struct hda_amp_list *p;
 	int ch, v;
 
 	if (!check->amplist)
@@ -4118,7 +4184,7 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
 				    -1);
 	snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
 	if (codec->slave_dig_outs) {
-		hda_nid_t *d;
+		const hda_nid_t *d;
 		for (d = codec->slave_dig_outs; *d; d++)
 			snd_hda_codec_setup_stream(codec, *d, stream_tag, 0,
 						   format);
@@ -4133,7 +4199,7 @@ static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid)
 {
 	snd_hda_codec_cleanup_stream(codec, nid);
 	if (codec->slave_dig_outs) {
-		hda_nid_t *d;
+		const hda_nid_t *d;
 		for (d = codec->slave_dig_outs; *d; d++)
 			snd_hda_codec_cleanup_stream(codec, *d);
 	}
@@ -4280,7 +4346,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
 				     unsigned int format,
 				     struct snd_pcm_substream *substream)
 {
-	hda_nid_t *nids = mout->dac_nids;
+	const hda_nid_t *nids = mout->dac_nids;
 	int chs = substream->runtime->channels;
 	int i;
 
@@ -4335,7 +4401,7 @@ EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_prepare);
 int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
 				     struct hda_multi_out *mout)
 {
-	hda_nid_t *nids = mout->dac_nids;
+	const hda_nid_t *nids = mout->dac_nids;
 	int i;
 
 	for (i = 0; i < mout->num_dacs; i++)
@@ -4360,7 +4426,7 @@ EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_cleanup);
  * Helper for automatic pin configuration
  */
 
-static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list)
+static int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list)
 {
 	for (; *list; list++)
 		if (*list == nid)
@@ -4441,7 +4507,7 @@ static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg)
  */
 int snd_hda_parse_pin_def_config(struct hda_codec *codec,
 				 struct auto_pin_cfg *cfg,
-				 hda_nid_t *ignore_nids)
+				 const hda_nid_t *ignore_nids)
 {
 	hda_nid_t nid, end_nid;
 	short seq, assoc_line_out, assoc_speaker;
@@ -4632,10 +4698,13 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
 	/*
 	 * debug prints of the parsed results
 	 */
-	snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
+	snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
 		   cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1],
 		   cfg->line_out_pins[2], cfg->line_out_pins[3],
-		   cfg->line_out_pins[4]);
+		   cfg->line_out_pins[4],
+		   cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" :
+		   (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ?
+		    "speaker" : "line"));
 	snd_printd("   speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
 		   cfg->speaker_outs, cfg->speaker_pins[0],
 		   cfg->speaker_pins[1], cfg->speaker_pins[2],
@@ -4986,6 +5055,8 @@ static const char *get_jack_default_name(struct hda_codec *codec, hda_nid_t nid,
 		return "Line-out";
 	case SND_JACK_HEADSET:
 		return "Headset";
+	case SND_JACK_VIDEOOUT:
+		return "HDMI/DP";
 	default:
 		return "Misc";
 	}
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index e46d5420a9f2..59c97306c1de 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -825,12 +825,14 @@ struct hda_codec {
 	struct hda_cache_rec amp_cache;	/* cache for amp access */
 	struct hda_cache_rec cmd_cache;	/* cache for other commands */
 
+	struct snd_array conn_lists;	/* connection-list array */
+
 	struct mutex spdif_mutex;
 	struct mutex control_mutex;
 	unsigned int spdif_status;	/* IEC958 status bits */
 	unsigned short spdif_ctls;	/* SPDIF control bits */
 	unsigned int spdif_in_enable;	/* SPDIF input enable? */
-	hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
+	const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
 	struct snd_array init_pins;	/* initial (BIOS) pin configurations */
 	struct snd_array driver_pins;	/* pin configs set by codec parser */
 	struct snd_array cvt_setups;	/* audio convert setups */
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 70a9d32f0e96..43a036716d25 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -126,6 +126,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
 			 "{Intel, ICH10},"
 			 "{Intel, PCH},"
 			 "{Intel, CPT},"
+			 "{Intel, PPT},"
 			 "{Intel, PBG},"
 			 "{Intel, SCH},"
 			 "{ATI, SB450},"
@@ -1091,7 +1092,13 @@ static void azx_init_pci(struct azx *chip)
 				? "Failed" : "OK");
 		}
 		break;
-
+	default:
+		/* AMD Hudson needs the similar snoop, as it seems... */
+		if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
+			update_pci_byte(chip->pci,
+				ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR,
+				0x07, ATI_SB450_HDAUDIO_ENABLE_SNOOP);
+		break;
         }
 }
 
@@ -1446,6 +1453,17 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
 		}
 	}
 
+	/* AMD chipsets often cause the communication stalls upon certain
+	 * sequence like the pin-detection.  It seems that forcing the synced
+	 * access works around the stall.  Grrr...
+	 */
+	if (chip->pci->vendor == PCI_VENDOR_ID_AMD ||
+	    chip->pci->vendor == PCI_VENDOR_ID_ATI) {
+		snd_printk(KERN_INFO SFX "Enable sync_write for AMD chipset\n");
+		chip->bus->sync_write = 1;
+		chip->bus->allow_bus_reset = 1;
+	}
+
 	/* Then create codec instances */
 	for (c = 0; c < max_slots; c++) {
 		if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
@@ -2349,9 +2367,16 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
 	/* Check VIA/ATI HD Audio Controller exist */
 	switch (chip->driver_type) {
 	case AZX_DRIVER_VIA:
-	case AZX_DRIVER_ATI:
 		/* Use link position directly, avoid any transfer problem. */
 		return POS_FIX_VIACOMBO;
+	case AZX_DRIVER_ATI:
+		/* ATI chipsets don't work well with position-buffer */
+		return POS_FIX_LPIB;
+	case AZX_DRIVER_GENERIC:
+		/* AMD chipsets also don't work with position-buffer */
+		if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
+			return POS_FIX_LPIB;
+		break;
 	}
 
 	return POS_FIX_AUTO;
@@ -2549,6 +2574,13 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
 				gcap &= ~ICH6_GCAP_64OK;
 			pci_dev_put(p_smbus);
 		}
+	} else {
+		/* FIXME: not sure whether this is really needed, but
+		 * Hudson isn't stable enough for allowing everything...
+		 * let's check later again.
+		 */
+		if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
+			gcap &= ~ICH6_GCAP_64OK;
 	}
 
 	/* disable 64bit DMA address for Teradici */
@@ -2759,6 +2791,8 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
 	{ PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH },
 	/* PBG */
 	{ PCI_DEVICE(0x8086, 0x1d20), .driver_data = AZX_DRIVER_PCH },
+	/* Panther Point */
+	{ PCI_DEVICE(0x8086, 0x1e20), .driver_data = AZX_DRIVER_PCH },
 	/* SCH */
 	{ PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH },
 	/* Generic Intel */
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index ff5e2ac2239a..08ec073444e2 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -267,11 +267,11 @@ enum { HDA_DIG_NONE, HDA_DIG_EXCLUSIVE, HDA_DIG_ANALOG_DUP }; /* dig_out_used */
 
 struct hda_multi_out {
 	int num_dacs;		/* # of DACs, must be more than 1 */
-	hda_nid_t *dac_nids;	/* DAC list */
+	const hda_nid_t *dac_nids;	/* DAC list */
 	hda_nid_t hp_nid;	/* optional DAC for HP, 0 when not exists */
 	hda_nid_t extra_out_nid[3];	/* optional DACs, 0 when not exists */
 	hda_nid_t dig_out_nid;	/* digital out audio widget */
-	hda_nid_t *slave_dig_outs;
+	const hda_nid_t *slave_dig_outs;
 	int max_channels;	/* currently supported analog channels */
 	int dig_out_used;	/* current usage of digital out (HDA_DIG_XXX) */
 	int no_share_stream;	/* don't share a stream with multiple pins */
@@ -347,7 +347,7 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
                                int num_configs, const char * const *models,
                                const struct snd_pci_quirk *tbl);
 int snd_hda_add_new_ctls(struct hda_codec *codec,
-			 struct snd_kcontrol_new *knew);
+			 const struct snd_kcontrol_new *knew);
 
 /*
  * unsolicited event handler
@@ -443,7 +443,7 @@ struct auto_pin_cfg {
 
 int snd_hda_parse_pin_def_config(struct hda_codec *codec,
 				 struct auto_pin_cfg *cfg,
-				 hda_nid_t *ignore_nids);
+				 const hda_nid_t *ignore_nids);
 
 /* amp values */
 #define AMP_IN_MUTE(idx)	(0x7080 | ((idx)<<8))
@@ -493,6 +493,12 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid);
 u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
 int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
 
+static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
+{
+	return (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT) &&
+		(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP);
+}
+
 /* flags for hda_nid_item */
 #define HDA_NID_ITEM_AMP	(1<<0)
 
@@ -567,7 +573,7 @@ struct hda_amp_list {
 };
 
 struct hda_loopback_check {
-	struct hda_amp_list *amplist;
+	const struct hda_amp_list *amplist;
 	int power_on;
 };
 
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 2942d2a9ea10..f1b3875c57df 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -30,7 +30,7 @@
 #include "hda_beep.h"
 
 struct ad198x_spec {
-	struct snd_kcontrol_new *mixers[6];
+	const struct snd_kcontrol_new *mixers[6];
 	int num_mixers;
 	unsigned int beep_amp;	/* beep amp value, set via set_beep_amp() */
 	const struct hda_verb *init_verbs[6];	/* initialization verbs
@@ -46,17 +46,17 @@ struct ad198x_spec {
 	unsigned int cur_eapd;
 	unsigned int need_dac_fix;
 
-	hda_nid_t *alt_dac_nid;
-	struct hda_pcm_stream *stream_analog_alt_playback;
+	const hda_nid_t *alt_dac_nid;
+	const struct hda_pcm_stream *stream_analog_alt_playback;
 
 	/* capture */
 	unsigned int num_adc_nids;
-	hda_nid_t *adc_nids;
+	const hda_nid_t *adc_nids;
 	hda_nid_t dig_in_nid;		/* digital-in NID; optional */
 
 	/* capture source */
 	const struct hda_input_mux *input_mux;
-	hda_nid_t *capsrc_nids;
+	const hda_nid_t *capsrc_nids;
 	unsigned int cur_mux[3];
 
 	/* channel model */
@@ -182,13 +182,13 @@ static void ad198x_free_kctls(struct hda_codec *codec);
 
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 /* additional beep mixers; the actual parameters are overwritten at build */
-static struct snd_kcontrol_new ad_beep_mixer[] = {
+static const struct snd_kcontrol_new ad_beep_mixer[] = {
 	HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new ad_beep2_mixer[] = {
+static const struct snd_kcontrol_new ad_beep2_mixer[] = {
 	HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT),
 	{ } /* end */
@@ -231,7 +231,7 @@ static int ad198x_build_controls(struct hda_codec *codec)
 	/* create beep controls if needed */
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 	if (spec->beep_amp) {
-		struct snd_kcontrol_new *knew;
+		const struct snd_kcontrol_new *knew;
 		knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer;
 		for ( ; knew->name; knew++) {
 			struct snd_kcontrol *kctl;
@@ -331,7 +331,7 @@ static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
 	return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
 }
 
-static struct hda_pcm_stream ad198x_pcm_analog_alt_playback = {
+static const struct hda_pcm_stream ad198x_pcm_analog_alt_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -403,7 +403,7 @@ static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 
 /*
  */
-static struct hda_pcm_stream ad198x_pcm_analog_playback = {
+static const struct hda_pcm_stream ad198x_pcm_analog_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 6, /* changed later */
@@ -415,7 +415,7 @@ static struct hda_pcm_stream ad198x_pcm_analog_playback = {
 	},
 };
 
-static struct hda_pcm_stream ad198x_pcm_analog_capture = {
+static const struct hda_pcm_stream ad198x_pcm_analog_capture = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -426,7 +426,7 @@ static struct hda_pcm_stream ad198x_pcm_analog_capture = {
 	},
 };
 
-static struct hda_pcm_stream ad198x_pcm_digital_playback = {
+static const struct hda_pcm_stream ad198x_pcm_digital_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -439,7 +439,7 @@ static struct hda_pcm_stream ad198x_pcm_digital_playback = {
 	},
 };
 
-static struct hda_pcm_stream ad198x_pcm_digital_capture = {
+static const struct hda_pcm_stream ad198x_pcm_digital_capture = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -489,11 +489,6 @@ static int ad198x_build_pcms(struct hda_codec *codec)
 	return 0;
 }
 
-static inline void ad198x_shutup(struct hda_codec *codec)
-{
-	snd_hda_shutup_pins(codec);
-}
-
 static void ad198x_free_kctls(struct hda_codec *codec)
 {
 	struct ad198x_spec *spec = codec->spec;
@@ -547,6 +542,12 @@ static void ad198x_power_eapd(struct hda_codec *codec)
 	}
 }
 
+static void ad198x_shutup(struct hda_codec *codec)
+{
+	snd_hda_shutup_pins(codec);
+	ad198x_power_eapd(codec);
+}
+
 static void ad198x_free(struct hda_codec *codec)
 {
 	struct ad198x_spec *spec = codec->spec;
@@ -564,12 +565,11 @@ static void ad198x_free(struct hda_codec *codec)
 static int ad198x_suspend(struct hda_codec *codec, pm_message_t state)
 {
 	ad198x_shutup(codec);
-	ad198x_power_eapd(codec);
 	return 0;
 }
 #endif
 
-static struct hda_codec_ops ad198x_patch_ops = {
+static const struct hda_codec_ops ad198x_patch_ops = {
 	.build_controls = ad198x_build_controls,
 	.build_pcms = ad198x_build_pcms,
 	.init = ad198x_init,
@@ -639,13 +639,13 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
 #define AD1986A_CLFE_DAC	0x05
 #define AD1986A_ADC		0x06
 
-static hda_nid_t ad1986a_dac_nids[3] = {
+static const hda_nid_t ad1986a_dac_nids[3] = {
 	AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
 };
-static hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
-static hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 };
+static const hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
+static const hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 };
 
-static struct hda_input_mux ad1986a_capture_source = {
+static const struct hda_input_mux ad1986a_capture_source = {
 	.num_items = 7,
 	.items = {
 		{ "Mic", 0x0 },
@@ -659,7 +659,7 @@ static struct hda_input_mux ad1986a_capture_source = {
 };
 
 
-static struct hda_bind_ctls ad1986a_bind_pcm_vol = {
+static const struct hda_bind_ctls ad1986a_bind_pcm_vol = {
 	.ops = &snd_hda_bind_vol,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
@@ -669,7 +669,7 @@ static struct hda_bind_ctls ad1986a_bind_pcm_vol = {
 	},
 };
 
-static struct hda_bind_ctls ad1986a_bind_pcm_sw = {
+static const struct hda_bind_ctls ad1986a_bind_pcm_sw = {
 	.ops = &snd_hda_bind_sw,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
@@ -682,7 +682,7 @@ static struct hda_bind_ctls ad1986a_bind_pcm_sw = {
 /*
  * mixers
  */
-static struct snd_kcontrol_new ad1986a_mixers[] = {
+static const struct snd_kcontrol_new ad1986a_mixers[] = {
 	/*
 	 * bind volumes/mutes of 3 DACs as a single PCM control for simplicity
 	 */
@@ -723,7 +723,7 @@ static struct snd_kcontrol_new ad1986a_mixers[] = {
 };
 
 /* additional mixers for 3stack mode */
-static struct snd_kcontrol_new ad1986a_3st_mixers[] = {
+static const struct snd_kcontrol_new ad1986a_3st_mixers[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Channel Mode",
@@ -735,10 +735,10 @@ static struct snd_kcontrol_new ad1986a_3st_mixers[] = {
 };
 
 /* laptop model - 2ch only */
-static hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC };
+static const hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC };
 
 /* master controls both pins 0x1a and 0x1b */
-static struct hda_bind_ctls ad1986a_laptop_master_vol = {
+static const struct hda_bind_ctls ad1986a_laptop_master_vol = {
 	.ops = &snd_hda_bind_vol,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
@@ -747,7 +747,7 @@ static struct hda_bind_ctls ad1986a_laptop_master_vol = {
 	},
 };
 
-static struct hda_bind_ctls ad1986a_laptop_master_sw = {
+static const struct hda_bind_ctls ad1986a_laptop_master_sw = {
 	.ops = &snd_hda_bind_sw,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
@@ -756,7 +756,7 @@ static struct hda_bind_ctls ad1986a_laptop_master_sw = {
 	},
 };
 
-static struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
+static const struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
@@ -787,7 +787,7 @@ static struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
 
 /* laptop-eapd model - 2ch only */
 
-static struct hda_input_mux ad1986a_laptop_eapd_capture_source = {
+static const struct hda_input_mux ad1986a_laptop_eapd_capture_source = {
 	.num_items = 3,
 	.items = {
 		{ "Mic", 0x0 },
@@ -796,7 +796,7 @@ static struct hda_input_mux ad1986a_laptop_eapd_capture_source = {
 	},
 };
 
-static struct hda_input_mux ad1986a_automic_capture_source = {
+static const struct hda_input_mux ad1986a_automic_capture_source = {
 	.num_items = 2,
 	.items = {
 		{ "Mic", 0x0 },
@@ -804,13 +804,13 @@ static struct hda_input_mux ad1986a_automic_capture_source = {
 	},
 };
 
-static struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = {
+static const struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = {
 	HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
 	HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
+static const struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
@@ -837,7 +837,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = {
+static const struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = {
 	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
 	{ } /* end */
@@ -931,7 +931,7 @@ static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol,
 	return change;
 }
 
-static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
+static const struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
 	HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -949,7 +949,7 @@ static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
 /*
  * initialization verbs
  */
-static struct hda_verb ad1986a_init_verbs[] = {
+static const struct hda_verb ad1986a_init_verbs[] = {
 	/* Front, Surround, CLFE DAC; mute as default */
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
@@ -1004,7 +1004,7 @@ static struct hda_verb ad1986a_init_verbs[] = {
 	{ } /* end */
 };
 
-static struct hda_verb ad1986a_ch2_init[] = {
+static const struct hda_verb ad1986a_ch2_init[] = {
 	/* Surround out -> Line In */
 	{ 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
  	/* Line-in selectors */
@@ -1016,7 +1016,7 @@ static struct hda_verb ad1986a_ch2_init[] = {
 	{ } /* end */
 };
 
-static struct hda_verb ad1986a_ch4_init[] = {
+static const struct hda_verb ad1986a_ch4_init[] = {
 	/* Surround out -> Surround */
 	{ 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
@@ -1026,7 +1026,7 @@ static struct hda_verb ad1986a_ch4_init[] = {
 	{ } /* end */
 };
 
-static struct hda_verb ad1986a_ch6_init[] = {
+static const struct hda_verb ad1986a_ch6_init[] = {
 	/* Surround out -> Surround out */
 	{ 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
@@ -1036,19 +1036,19 @@ static struct hda_verb ad1986a_ch6_init[] = {
 	{ } /* end */
 };
 
-static struct hda_channel_mode ad1986a_modes[3] = {
+static const struct hda_channel_mode ad1986a_modes[3] = {
 	{ 2, ad1986a_ch2_init },
 	{ 4, ad1986a_ch4_init },
 	{ 6, ad1986a_ch6_init },
 };
 
 /* eapd initialization */
-static struct hda_verb ad1986a_eapd_init_verbs[] = {
+static const struct hda_verb ad1986a_eapd_init_verbs[] = {
 	{0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
 	{}
 };
 
-static struct hda_verb ad1986a_automic_verbs[] = {
+static const struct hda_verb ad1986a_automic_verbs[] = {
 	{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
 	{0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
 	/*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/
@@ -1058,7 +1058,7 @@ static struct hda_verb ad1986a_automic_verbs[] = {
 };
 
 /* Ultra initialization */
-static struct hda_verb ad1986a_ultra_init[] = {
+static const struct hda_verb ad1986a_ultra_init[] = {
 	/* eapd initialization */
 	{ 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
 	/* CLFE -> Mic in */
@@ -1069,7 +1069,7 @@ static struct hda_verb ad1986a_ultra_init[] = {
 };
 
 /* pin sensing on HP jack */
-static struct hda_verb ad1986a_hp_init_verbs[] = {
+static const struct hda_verb ad1986a_hp_init_verbs[] = {
 	{0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT},
 	{}
 };
@@ -1120,7 +1120,7 @@ static const char * const ad1986a_models[AD1986A_MODELS] = {
 	[AD1986A_SAMSUNG_P50]	= "samsung-p50",
 };
 
-static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
+static const struct snd_pci_quirk ad1986a_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
 	SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD),
 	SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD),
@@ -1152,7 +1152,7 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
 };
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list ad1986a_loopbacks[] = {
+static const struct hda_amp_list ad1986a_loopbacks[] = {
 	{ 0x13, HDA_OUTPUT, 0 }, /* Mic */
 	{ 0x14, HDA_OUTPUT, 0 }, /* Phone */
 	{ 0x15, HDA_OUTPUT, 0 }, /* CD */
@@ -1329,11 +1329,11 @@ static int patch_ad1986a(struct hda_codec *codec)
 #define AD1983_DAC		0x03
 #define AD1983_ADC		0x04
 
-static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC };
-static hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC };
-static hda_nid_t ad1983_capsrc_nids[1] = { 0x15 };
+static const hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC };
+static const hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC };
+static const hda_nid_t ad1983_capsrc_nids[1] = { 0x15 };
 
-static struct hda_input_mux ad1983_capture_source = {
+static const struct hda_input_mux ad1983_capture_source = {
 	.num_items = 4,
 	.items = {
 		{ "Mic", 0x0 },
@@ -1348,7 +1348,7 @@ static struct hda_input_mux ad1983_capture_source = {
  */
 static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = { "PCM", "ADC" };
+	static const char * const texts[] = { "PCM", "ADC" };
 
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
@@ -1385,7 +1385,7 @@ static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
 	return 0;
 }
 
-static struct snd_kcontrol_new ad1983_mixers[] = {
+static const struct snd_kcontrol_new ad1983_mixers[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
@@ -1418,7 +1418,7 @@ static struct snd_kcontrol_new ad1983_mixers[] = {
 	{ } /* end */
 };
 
-static struct hda_verb ad1983_init_verbs[] = {
+static const struct hda_verb ad1983_init_verbs[] = {
 	/* Front, HP, Mono; mute as default */
 	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
@@ -1458,7 +1458,7 @@ static struct hda_verb ad1983_init_verbs[] = {
 };
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list ad1983_loopbacks[] = {
+static const struct hda_amp_list ad1983_loopbacks[] = {
 	{ 0x12, HDA_OUTPUT, 0 }, /* Mic */
 	{ 0x13, HDA_OUTPUT, 0 }, /* Line */
 	{ } /* end */
@@ -1518,12 +1518,12 @@ static int patch_ad1983(struct hda_codec *codec)
 #define AD1981_DAC		0x03
 #define AD1981_ADC		0x04
 
-static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
-static hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC };
-static hda_nid_t ad1981_capsrc_nids[1] = { 0x15 };
+static const hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
+static const hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC };
+static const hda_nid_t ad1981_capsrc_nids[1] = { 0x15 };
 
 /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */
-static struct hda_input_mux ad1981_capture_source = {
+static const struct hda_input_mux ad1981_capture_source = {
 	.num_items = 7,
 	.items = {
 		{ "Front Mic", 0x0 },
@@ -1536,7 +1536,7 @@ static struct hda_input_mux ad1981_capture_source = {
 	},
 };
 
-static struct snd_kcontrol_new ad1981_mixers[] = {
+static const struct snd_kcontrol_new ad1981_mixers[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
@@ -1577,7 +1577,7 @@ static struct snd_kcontrol_new ad1981_mixers[] = {
 	{ } /* end */
 };
 
-static struct hda_verb ad1981_init_verbs[] = {
+static const struct hda_verb ad1981_init_verbs[] = {
 	/* Front, HP, Mono; mute as default */
 	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
@@ -1625,7 +1625,7 @@ static struct hda_verb ad1981_init_verbs[] = {
 };
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list ad1981_loopbacks[] = {
+static const struct hda_amp_list ad1981_loopbacks[] = {
 	{ 0x12, HDA_OUTPUT, 0 }, /* Front Mic */
 	{ 0x13, HDA_OUTPUT, 0 }, /* Line */
 	{ 0x1b, HDA_OUTPUT, 0 }, /* Aux */
@@ -1645,7 +1645,7 @@ static struct hda_amp_list ad1981_loopbacks[] = {
 #define AD1981_HP_EVENT		0x37
 #define AD1981_MIC_EVENT	0x38
 
-static struct hda_verb ad1981_hp_init_verbs[] = {
+static const struct hda_verb ad1981_hp_init_verbs[] = {
 	{0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */
 	/* pin sensing on HP and Mic jacks */
 	{0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
@@ -1674,7 +1674,7 @@ static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol,
 }
 
 /* bind volumes of both NID 0x05 and 0x06 */
-static struct hda_bind_ctls ad1981_hp_bind_master_vol = {
+static const struct hda_bind_ctls ad1981_hp_bind_master_vol = {
 	.ops = &snd_hda_bind_vol,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
@@ -1696,12 +1696,12 @@ static void ad1981_hp_automute(struct hda_codec *codec)
 /* toggle input of built-in and mic jack appropriately */
 static void ad1981_hp_automic(struct hda_codec *codec)
 {
-	static struct hda_verb mic_jack_on[] = {
+	static const struct hda_verb mic_jack_on[] = {
 		{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 		{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
 		{}
 	};
-	static struct hda_verb mic_jack_off[] = {
+	static const struct hda_verb mic_jack_off[] = {
 		{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 		{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
 		{}
@@ -1730,7 +1730,7 @@ static void ad1981_hp_unsol_event(struct hda_codec *codec,
 	}
 }
 
-static struct hda_input_mux ad1981_hp_capture_source = {
+static const struct hda_input_mux ad1981_hp_capture_source = {
 	.num_items = 3,
 	.items = {
 		{ "Mic", 0x0 },
@@ -1739,7 +1739,7 @@ static struct hda_input_mux ad1981_hp_capture_source = {
 	},
 };
 
-static struct snd_kcontrol_new ad1981_hp_mixers[] = {
+static const struct snd_kcontrol_new ad1981_hp_mixers[] = {
 	HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -1790,7 +1790,7 @@ static int ad1981_hp_init(struct hda_codec *codec)
 }
 
 /* configuration for Toshiba Laptops */
-static struct hda_verb ad1981_toshiba_init_verbs[] = {
+static const struct hda_verb ad1981_toshiba_init_verbs[] = {
 	{0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */
 	/* pin sensing on HP and Mic jacks */
 	{0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
@@ -1798,14 +1798,14 @@ static struct hda_verb ad1981_toshiba_init_verbs[] = {
 	{}
 };
 
-static struct snd_kcontrol_new ad1981_toshiba_mixers[] = {
+static const struct snd_kcontrol_new ad1981_toshiba_mixers[] = {
 	HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT),
 	{ }
 };
 
 /* configuration for Lenovo Thinkpad T60 */
-static struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
+static const struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
@@ -1835,7 +1835,7 @@ static struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
 	{ } /* end */
 };
 
-static struct hda_input_mux ad1981_thinkpad_capture_source = {
+static const struct hda_input_mux ad1981_thinkpad_capture_source = {
 	.num_items = 3,
 	.items = {
 		{ "Mic", 0x0 },
@@ -1860,7 +1860,7 @@ static const char * const ad1981_models[AD1981_MODELS] = {
 	[AD1981_TOSHIBA]	= "toshiba"
 };
 
-static struct snd_pci_quirk ad1981_cfg_tbl[] = {
+static const struct snd_pci_quirk ad1981_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
 	SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
 	/* All HP models */
@@ -2075,32 +2075,32 @@ enum {
  * mixers
  */
 
-static hda_nid_t ad1988_6stack_dac_nids[4] = {
+static const hda_nid_t ad1988_6stack_dac_nids[4] = {
 	0x04, 0x06, 0x05, 0x0a
 };
 
-static hda_nid_t ad1988_3stack_dac_nids[3] = {
+static const hda_nid_t ad1988_3stack_dac_nids[3] = {
 	0x04, 0x05, 0x0a
 };
 
 /* for AD1988A revision-2, DAC2-4 are swapped */
-static hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {
+static const hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {
 	0x04, 0x05, 0x0a, 0x06
 };
 
-static hda_nid_t ad1988_alt_dac_nid[1] = {
+static const hda_nid_t ad1988_alt_dac_nid[1] = {
 	0x03
 };
 
-static hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {
+static const hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {
 	0x04, 0x0a, 0x06
 };
 
-static hda_nid_t ad1988_adc_nids[3] = {
+static const hda_nid_t ad1988_adc_nids[3] = {
 	0x08, 0x09, 0x0f
 };
 
-static hda_nid_t ad1988_capsrc_nids[3] = {
+static const hda_nid_t ad1988_capsrc_nids[3] = {
 	0x0c, 0x0d, 0x0e
 };
 
@@ -2108,11 +2108,11 @@ static hda_nid_t ad1988_capsrc_nids[3] = {
 #define AD1988_SPDIF_OUT_HDMI	0x0b
 #define AD1988_SPDIF_IN		0x07
 
-static hda_nid_t ad1989b_slave_dig_outs[] = {
+static const hda_nid_t ad1989b_slave_dig_outs[] = {
 	AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0
 };
 
-static struct hda_input_mux ad1988_6stack_capture_source = {
+static const struct hda_input_mux ad1988_6stack_capture_source = {
 	.num_items = 5,
 	.items = {
 		{ "Front Mic", 0x1 },	/* port-B */
@@ -2123,7 +2123,7 @@ static struct hda_input_mux ad1988_6stack_capture_source = {
 	},
 };
 
-static struct hda_input_mux ad1988_laptop_capture_source = {
+static const struct hda_input_mux ad1988_laptop_capture_source = {
 	.num_items = 3,
 	.items = {
 		{ "Mic/Line", 0x1 },	/* port-B */
@@ -2166,7 +2166,7 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
 }
 
 /* 6-stack mode */
-static struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
+static const struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
@@ -2175,7 +2175,7 @@ static struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = {
+static const struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
@@ -2184,7 +2184,7 @@ static struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
+static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
 	HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
 	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
@@ -2211,14 +2211,14 @@ static struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = {
+static const struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = {
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 
 	{ } /* end */
 };
 
 /* 3-stack mode */
-static struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
+static const struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
@@ -2226,7 +2226,7 @@ static struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = {
+static const struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT),
@@ -2234,7 +2234,7 @@ static struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
+static const struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
 	HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT),
 	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT),
@@ -2268,7 +2268,7 @@ static struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
 };
 
 /* laptop mode */
-static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
+static const struct snd_kcontrol_new ad1988_laptop_mixers[] = {
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT),
 	HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
@@ -2299,7 +2299,7 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
 };
 
 /* capture */
-static struct snd_kcontrol_new ad1988_capture_mixers[] = {
+static const struct snd_kcontrol_new ad1988_capture_mixers[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
@@ -2324,7 +2324,7 @@ static struct snd_kcontrol_new ad1988_capture_mixers[] = {
 static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol,
 					     struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = {
+	static const char * const texts[] = {
 		"PCM", "ADC1", "ADC2", "ADC3"
 	};
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
@@ -2405,7 +2405,7 @@ static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol,
 	return change;
 }
 
-static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
+static const struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
 	HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -2418,12 +2418,12 @@ static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new ad1988_spdif_in_mixers[] = {
+static const struct snd_kcontrol_new ad1988_spdif_in_mixers[] = {
 	HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT),
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
+static const struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
 	HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
 	{ } /* end */
@@ -2436,7 +2436,7 @@ static struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
 /*
  * for 6-stack (+dig)
  */
-static struct hda_verb ad1988_6stack_init_verbs[] = {
+static const struct hda_verb ad1988_6stack_init_verbs[] = {
 	/* Front, Surround, CLFE, side DAC; unmute as default */
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -2496,7 +2496,7 @@ static struct hda_verb ad1988_6stack_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb ad1988_6stack_fp_init_verbs[] = {
+static const struct hda_verb ad1988_6stack_fp_init_verbs[] = {
 	/* Headphone; unmute as default */
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	/* Port-A front headphon path */
@@ -2509,7 +2509,7 @@ static struct hda_verb ad1988_6stack_fp_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb ad1988_capture_init_verbs[] = {
+static const struct hda_verb ad1988_capture_init_verbs[] = {
 	/* mute analog mix */
 	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
@@ -2527,7 +2527,7 @@ static struct hda_verb ad1988_capture_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb ad1988_spdif_init_verbs[] = {
+static const struct hda_verb ad1988_spdif_init_verbs[] = {
 	/* SPDIF out sel */
 	{0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
 	{0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */
@@ -2539,14 +2539,14 @@ static struct hda_verb ad1988_spdif_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb ad1988_spdif_in_init_verbs[] = {
+static const struct hda_verb ad1988_spdif_in_init_verbs[] = {
 	/* unmute SPDIF input pin */
 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{ }
 };
 
 /* AD1989 has no ADC -> SPDIF route */
-static struct hda_verb ad1989_spdif_init_verbs[] = {
+static const struct hda_verb ad1989_spdif_init_verbs[] = {
 	/* SPDIF-1 out pin */
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
@@ -2559,7 +2559,7 @@ static struct hda_verb ad1989_spdif_init_verbs[] = {
 /*
  * verbs for 3stack (+dig)
  */
-static struct hda_verb ad1988_3stack_ch2_init[] = {
+static const struct hda_verb ad1988_3stack_ch2_init[] = {
 	/* set port-C to line-in */
 	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
@@ -2569,7 +2569,7 @@ static struct hda_verb ad1988_3stack_ch2_init[] = {
 	{ } /* end */
 };
 
-static struct hda_verb ad1988_3stack_ch6_init[] = {
+static const struct hda_verb ad1988_3stack_ch6_init[] = {
 	/* set port-C to surround out */
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
@@ -2579,12 +2579,12 @@ static struct hda_verb ad1988_3stack_ch6_init[] = {
 	{ } /* end */
 };
 
-static struct hda_channel_mode ad1988_3stack_modes[2] = {
+static const struct hda_channel_mode ad1988_3stack_modes[2] = {
 	{ 2, ad1988_3stack_ch2_init },
 	{ 6, ad1988_3stack_ch6_init },
 };
 
-static struct hda_verb ad1988_3stack_init_verbs[] = {
+static const struct hda_verb ad1988_3stack_init_verbs[] = {
 	/* Front, Surround, CLFE, side DAC; unmute as default */
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -2644,13 +2644,13 @@ static struct hda_verb ad1988_3stack_init_verbs[] = {
 /*
  * verbs for laptop mode (+dig)
  */
-static struct hda_verb ad1988_laptop_hp_on[] = {
+static const struct hda_verb ad1988_laptop_hp_on[] = {
 	/* unmute port-A and mute port-D */
 	{ 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ } /* end */
 };
-static struct hda_verb ad1988_laptop_hp_off[] = {
+static const struct hda_verb ad1988_laptop_hp_off[] = {
 	/* mute port-A and unmute port-D */
 	{ 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
@@ -2659,7 +2659,7 @@ static struct hda_verb ad1988_laptop_hp_off[] = {
 
 #define AD1988_HP_EVENT	0x01
 
-static struct hda_verb ad1988_laptop_init_verbs[] = {
+static const struct hda_verb ad1988_laptop_init_verbs[] = {
 	/* Front, Surround, CLFE, side DAC; unmute as default */
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -2723,7 +2723,7 @@ static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)
 } 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list ad1988_loopbacks[] = {
+static const struct hda_amp_list ad1988_loopbacks[] = {
 	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
 	{ 0x20, HDA_INPUT, 1 }, /* Line */
 	{ 0x20, HDA_INPUT, 4 }, /* Mic */
@@ -2741,7 +2741,7 @@ enum {
 	AD_CTL_WIDGET_MUTE,
 	AD_CTL_BIND_MUTE,
 };
-static struct snd_kcontrol_new ad1988_control_templates[] = {
+static const struct snd_kcontrol_new ad1988_control_templates[] = {
 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
 	HDA_CODEC_MUTE(NULL, 0, 0, 0),
 	HDA_BIND_MUTE(NULL, 0, 0, 0),
@@ -2770,18 +2770,18 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name,
 #define AD1988_PIN_CD_NID		0x18
 #define AD1988_PIN_BEEP_NID		0x10
 
-static hda_nid_t ad1988_mixer_nids[8] = {
+static const hda_nid_t ad1988_mixer_nids[8] = {
 	/* A     B     C     D     E     F     G     H */
 	0x22, 0x2b, 0x2c, 0x29, 0x26, 0x2a, 0x27, 0x28
 };
 
 static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx)
 {
-	static hda_nid_t idx_to_dac[8] = {
+	static const hda_nid_t idx_to_dac[8] = {
 		/* A     B     C     D     E     F     G     H */
 		0x04, 0x06, 0x05, 0x04, 0x0a, 0x06, 0x05, 0x0a
 	};
-	static hda_nid_t idx_to_dac_rev2[8] = {
+	static const hda_nid_t idx_to_dac_rev2[8] = {
 		/* A     B     C     D     E     F     G     H */
 		0x04, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06
 	};
@@ -2791,13 +2791,13 @@ static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx)
 		return idx_to_dac[idx];
 }
 
-static hda_nid_t ad1988_boost_nids[8] = {
+static const hda_nid_t ad1988_boost_nids[8] = {
 	0x38, 0x39, 0x3a, 0x3d, 0x3c, 0x3b, 0, 0
 };
 
 static int ad1988_pin_idx(hda_nid_t nid)
 {
-	static hda_nid_t ad1988_io_pins[8] = {
+	static const hda_nid_t ad1988_io_pins[8] = {
 		0x11, 0x14, 0x15, 0x12, 0x17, 0x16, 0x24, 0x25
 	};
 	int i;
@@ -2809,7 +2809,7 @@ static int ad1988_pin_idx(hda_nid_t nid)
 
 static int ad1988_pin_to_loopback_idx(hda_nid_t nid)
 {
-	static int loopback_idx[8] = {
+	static const int loopback_idx[8] = {
 		2, 0, 1, 3, 4, 5, 1, 4
 	};
 	switch (nid) {
@@ -2822,7 +2822,7 @@ static int ad1988_pin_to_loopback_idx(hda_nid_t nid)
 
 static int ad1988_pin_to_adc_idx(hda_nid_t nid)
 {
-	static int adc_idx[8] = {
+	static const int adc_idx[8] = {
 		0, 1, 2, 8, 4, 3, 6, 7
 	};
 	switch (nid) {
@@ -2845,7 +2845,7 @@ static int ad1988_auto_fill_dac_nids(struct hda_codec *codec,
 	/* check the pins hardwired to audio widget */
 	for (i = 0; i < cfg->line_outs; i++) {
 		idx = ad1988_pin_idx(cfg->line_out_pins[i]);
-		spec->multiout.dac_nids[i] = ad1988_idx_to_dac(codec, idx);
+		spec->private_dac_nids[i] = ad1988_idx_to_dac(codec, idx);
 	}
 	spec->multiout.num_dacs = cfg->line_outs;
 	return 0;
@@ -3070,6 +3070,7 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec)
 
 	for (i = 0; i < cfg->num_inputs; i++) {
 		hda_nid_t nid = cfg->inputs[i].pin;
+		int type = cfg->inputs[i].type;
 		switch (nid) {
 		case 0x15: /* port-C */
 			snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
@@ -3079,7 +3080,7 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec)
 			break;
 		}
 		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-				    i == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN);
+				    type == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN);
 		if (nid != AD1988_PIN_CD_NID)
 			snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
 					    AMP_OUT_MUTE);
@@ -3154,7 +3155,7 @@ static const char * const ad1988_models[AD1988_MODEL_LAST] = {
 	[AD1988_AUTO]		= "auto",
 };
 
-static struct snd_pci_quirk ad1988_cfg_tbl[] = {
+static const struct snd_pci_quirk ad1988_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
 	SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
 	SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG),
@@ -3342,21 +3343,21 @@ static int patch_ad1988(struct hda_codec *codec)
  * but no build-up framework is given, so far.
  */
 
-static hda_nid_t ad1884_dac_nids[1] = {
+static const hda_nid_t ad1884_dac_nids[1] = {
 	0x04,
 };
 
-static hda_nid_t ad1884_adc_nids[2] = {
+static const hda_nid_t ad1884_adc_nids[2] = {
 	0x08, 0x09,
 };
 
-static hda_nid_t ad1884_capsrc_nids[2] = {
+static const hda_nid_t ad1884_capsrc_nids[2] = {
 	0x0c, 0x0d,
 };
 
 #define AD1884_SPDIF_OUT	0x02
 
-static struct hda_input_mux ad1884_capture_source = {
+static const struct hda_input_mux ad1884_capture_source = {
 	.num_items = 4,
 	.items = {
 		{ "Front Mic", 0x0 },
@@ -3366,7 +3367,7 @@ static struct hda_input_mux ad1884_capture_source = {
 	},
 };
 
-static struct snd_kcontrol_new ad1884_base_mixers[] = {
+static const struct snd_kcontrol_new ad1884_base_mixers[] = {
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	/* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
@@ -3410,7 +3411,7 @@ static struct snd_kcontrol_new ad1884_base_mixers[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new ad1984_dmic_mixers[] = {
+static const struct snd_kcontrol_new ad1984_dmic_mixers[] = {
 	HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0,
@@ -3423,7 +3424,7 @@ static struct snd_kcontrol_new ad1984_dmic_mixers[] = {
 /*
  * initialization verbs
  */
-static struct hda_verb ad1884_init_verbs[] = {
+static const struct hda_verb ad1884_init_verbs[] = {
 	/* DACs; mute as default */
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
@@ -3469,7 +3470,7 @@ static struct hda_verb ad1884_init_verbs[] = {
 };
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list ad1884_loopbacks[] = {
+static const struct hda_amp_list ad1884_loopbacks[] = {
 	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
 	{ 0x20, HDA_INPUT, 1 }, /* Mic */
 	{ 0x20, HDA_INPUT, 2 }, /* CD */
@@ -3541,7 +3542,7 @@ static int patch_ad1884(struct hda_codec *codec)
 /*
  * Lenovo Thinkpad T61/X61
  */
-static struct hda_input_mux ad1984_thinkpad_capture_source = {
+static const struct hda_input_mux ad1984_thinkpad_capture_source = {
 	.num_items = 4,
 	.items = {
 		{ "Mic", 0x0 },
@@ -3555,7 +3556,7 @@ static struct hda_input_mux ad1984_thinkpad_capture_source = {
 /*
  * Dell Precision T3400
  */
-static struct hda_input_mux ad1984_dell_desktop_capture_source = {
+static const struct hda_input_mux ad1984_dell_desktop_capture_source = {
 	.num_items = 3,
 	.items = {
 		{ "Front Mic", 0x0 },
@@ -3565,7 +3566,7 @@ static struct hda_input_mux ad1984_dell_desktop_capture_source = {
 };
 
 
-static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
+static const struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	/* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
@@ -3611,7 +3612,7 @@ static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
 };
 
 /* additional verbs */
-static struct hda_verb ad1984_thinkpad_init_verbs[] = {
+static const struct hda_verb ad1984_thinkpad_init_verbs[] = {
 	/* Port-E (docking station mic) pin */
 	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
@@ -3629,7 +3630,7 @@ static struct hda_verb ad1984_thinkpad_init_verbs[] = {
 /*
  * Dell Precision T3400
  */
-static struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
+static const struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
@@ -3680,7 +3681,7 @@ static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo,
 	return 0;
 }
 
-static struct hda_pcm_stream ad1984_pcm_dmic_capture = {
+static const struct hda_pcm_stream ad1984_pcm_dmic_capture = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -3722,7 +3723,7 @@ static const char * const ad1984_models[AD1984_MODELS] = {
 	[AD1984_DELL_DESKTOP]	= "dell_desktop",
 };
 
-static struct snd_pci_quirk ad1984_cfg_tbl[] = {
+static const struct snd_pci_quirk ad1984_cfg_tbl[] = {
 	/* Lenovo Thinkpad T61/X61 */
 	SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD),
 	SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
@@ -3787,7 +3788,7 @@ static int patch_ad1984(struct hda_codec *codec)
  * We share the single DAC for both HP and line-outs (see AD1884/1984).
  */
 
-static hda_nid_t ad1884a_dac_nids[1] = {
+static const hda_nid_t ad1884a_dac_nids[1] = {
 	0x03,
 };
 
@@ -3796,7 +3797,7 @@ static hda_nid_t ad1884a_dac_nids[1] = {
 
 #define AD1884A_SPDIF_OUT	0x02
 
-static struct hda_input_mux ad1884a_capture_source = {
+static const struct hda_input_mux ad1884a_capture_source = {
 	.num_items = 5,
 	.items = {
 		{ "Front Mic", 0x0 },
@@ -3807,7 +3808,7 @@ static struct hda_input_mux ad1884a_capture_source = {
 	},
 };
 
-static struct snd_kcontrol_new ad1884a_base_mixers[] = {
+static const struct snd_kcontrol_new ad1884a_base_mixers[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
@@ -3859,7 +3860,7 @@ static struct snd_kcontrol_new ad1884a_base_mixers[] = {
 /*
  * initialization verbs
  */
-static struct hda_verb ad1884a_init_verbs[] = {
+static const struct hda_verb ad1884a_init_verbs[] = {
 	/* DACs; unmute as default */
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
@@ -3914,7 +3915,7 @@ static struct hda_verb ad1884a_init_verbs[] = {
 };
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list ad1884a_loopbacks[] = {
+static const struct hda_amp_list ad1884a_loopbacks[] = {
 	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
 	{ 0x20, HDA_INPUT, 1 }, /* Mic */
 	{ 0x20, HDA_INPUT, 2 }, /* CD */
@@ -3947,7 +3948,7 @@ static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
 	return ret;
 }
 
-static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
+static const struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -3975,7 +3976,7 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
+static const struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
 	/*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
 	{
@@ -4095,7 +4096,7 @@ static int ad1884a_laptop_init(struct hda_codec *codec)
 }
 
 /* additional verbs for laptop model */
-static struct hda_verb ad1884a_laptop_verbs[] = {
+static const struct hda_verb ad1884a_laptop_verbs[] = {
 	/* Port-A (HP) pin - always unmuted */
 	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	/* Port-F (int speaker) mixer - route only from analog mixer */
@@ -4126,7 +4127,7 @@ static struct hda_verb ad1884a_laptop_verbs[] = {
 	{ } /* end */
 };
 
-static struct hda_verb ad1884a_mobile_verbs[] = {
+static const struct hda_verb ad1884a_mobile_verbs[] = {
 	/* DACs; unmute as default */
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
@@ -4181,7 +4182,7 @@ static struct hda_verb ad1884a_mobile_verbs[] = {
  * 0x17 - built-in mic
  */
 
-static struct hda_verb ad1984a_thinkpad_verbs[] = {
+static const struct hda_verb ad1984a_thinkpad_verbs[] = {
 	/* HP unmute */
 	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	/* analog mix */
@@ -4198,7 +4199,7 @@ static struct hda_verb ad1984a_thinkpad_verbs[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
+static const struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
@@ -4219,7 +4220,7 @@ static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
 	{ } /* end */
 };
 
-static struct hda_input_mux ad1984a_thinkpad_capture_source = {
+static const struct hda_input_mux ad1984a_thinkpad_capture_source = {
 	.num_items = 3,
 	.items = {
 		{ "Mic", 0x0 },
@@ -4262,7 +4263,7 @@ static int ad1984a_thinkpad_init(struct hda_codec *codec)
  * 0x15 - mic-in
  */
 
-static struct hda_verb ad1984a_precision_verbs[] = {
+static const struct hda_verb ad1984a_precision_verbs[] = {
 	/* Unmute main output path */
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x1f}, /* 0dB */
@@ -4288,7 +4289,7 @@ static struct hda_verb ad1984a_precision_verbs[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new ad1984a_precision_mixers[] = {
+static const struct snd_kcontrol_new ad1984a_precision_mixers[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
@@ -4344,7 +4345,7 @@ static int ad1984a_precision_init(struct hda_codec *codec)
  * digital-mic (0x17) - Internal mic
  */
 
-static struct hda_verb ad1984a_touchsmart_verbs[] = {
+static const struct hda_verb ad1984a_touchsmart_verbs[] = {
 	/* DACs; unmute as default */
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
@@ -4396,7 +4397,7 @@ static struct hda_verb ad1984a_touchsmart_verbs[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
+static const struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
 /*	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
 	{
@@ -4475,7 +4476,7 @@ static const char * const ad1884a_models[AD1884A_MODELS] = {
 	[AD1984A_PRECISION]	= "precision",
 };
 
-static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
+static const struct snd_pci_quirk ad1884a_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1028, 0x04ac, "Precision R5500", AD1984A_PRECISION),
 	SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
 	SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
@@ -4614,22 +4615,22 @@ static int patch_ad1884a(struct hda_codec *codec)
  * port-G - rear clfe-out (6stack)
  */
 
-static hda_nid_t ad1882_dac_nids[3] = {
+static const hda_nid_t ad1882_dac_nids[3] = {
 	0x04, 0x03, 0x05
 };
 
-static hda_nid_t ad1882_adc_nids[2] = {
+static const hda_nid_t ad1882_adc_nids[2] = {
 	0x08, 0x09,
 };
 
-static hda_nid_t ad1882_capsrc_nids[2] = {
+static const hda_nid_t ad1882_capsrc_nids[2] = {
 	0x0c, 0x0d,
 };
 
 #define AD1882_SPDIF_OUT	0x02
 
 /* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */
-static struct hda_input_mux ad1882_capture_source = {
+static const struct hda_input_mux ad1882_capture_source = {
 	.num_items = 5,
 	.items = {
 		{ "Front Mic", 0x1 },
@@ -4641,7 +4642,7 @@ static struct hda_input_mux ad1882_capture_source = {
 };
 
 /* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */
-static struct hda_input_mux ad1882a_capture_source = {
+static const struct hda_input_mux ad1882a_capture_source = {
 	.num_items = 5,
 	.items = {
 		{ "Front Mic", 0x1 },
@@ -4652,7 +4653,7 @@ static struct hda_input_mux ad1882a_capture_source = {
 	},
 };
 
-static struct snd_kcontrol_new ad1882_base_mixers[] = {
+static const struct snd_kcontrol_new ad1882_base_mixers[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
@@ -4694,7 +4695,7 @@ static struct snd_kcontrol_new ad1882_base_mixers[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new ad1882_loopback_mixers[] = {
+static const struct snd_kcontrol_new ad1882_loopback_mixers[] = {
 	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
@@ -4706,7 +4707,7 @@ static struct snd_kcontrol_new ad1882_loopback_mixers[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
+static const struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
 	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
@@ -4719,7 +4720,7 @@ static struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new ad1882_3stack_mixers[] = {
+static const struct snd_kcontrol_new ad1882_3stack_mixers[] = {
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT),
@@ -4733,14 +4734,14 @@ static struct snd_kcontrol_new ad1882_3stack_mixers[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new ad1882_6stack_mixers[] = {
+static const struct snd_kcontrol_new ad1882_6stack_mixers[] = {
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT),
 	{ } /* end */
 };
 
-static struct hda_verb ad1882_ch2_init[] = {
+static const struct hda_verb ad1882_ch2_init[] = {
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
@@ -4750,7 +4751,7 @@ static struct hda_verb ad1882_ch2_init[] = {
 	{ } /* end */
 };
 
-static struct hda_verb ad1882_ch4_init[] = {
+static const struct hda_verb ad1882_ch4_init[] = {
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -4760,7 +4761,7 @@ static struct hda_verb ad1882_ch4_init[] = {
 	{ } /* end */
 };
 
-static struct hda_verb ad1882_ch6_init[] = {
+static const struct hda_verb ad1882_ch6_init[] = {
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -4770,7 +4771,7 @@ static struct hda_verb ad1882_ch6_init[] = {
 	{ } /* end */
 };
 
-static struct hda_channel_mode ad1882_modes[3] = {
+static const struct hda_channel_mode ad1882_modes[3] = {
 	{ 2, ad1882_ch2_init },
 	{ 4, ad1882_ch4_init },
 	{ 6, ad1882_ch6_init },
@@ -4779,7 +4780,7 @@ static struct hda_channel_mode ad1882_modes[3] = {
 /*
  * initialization verbs
  */
-static struct hda_verb ad1882_init_verbs[] = {
+static const struct hda_verb ad1882_init_verbs[] = {
 	/* DACs; mute as default */
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
@@ -4848,7 +4849,7 @@ static struct hda_verb ad1882_init_verbs[] = {
 };
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list ad1882_loopbacks[] = {
+static const struct hda_amp_list ad1882_loopbacks[] = {
 	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
 	{ 0x20, HDA_INPUT, 1 }, /* Mic */
 	{ 0x20, HDA_INPUT, 4 }, /* Line */
@@ -4945,7 +4946,7 @@ static int patch_ad1882(struct hda_codec *codec)
 /*
  * patch entries
  */
-static struct hda_codec_preset snd_hda_preset_analog[] = {
+static const struct hda_codec_preset snd_hda_preset_analog[] = {
 	{ .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
 	{ .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
 	{ .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },
diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c
index 46c8bf48c31f..61b92634b161 100644
--- a/sound/pci/hda/patch_ca0110.c
+++ b/sound/pci/hda/patch_ca0110.c
@@ -134,7 +134,7 @@ static int ca0110_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 /*
  */
 
-static char *dirstr[2] = { "Playback", "Capture" };
+static const char * const dirstr[2] = { "Playback", "Capture" };
 
 static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
 		       int chan, int dir)
@@ -171,7 +171,7 @@ static int ca0110_build_controls(struct hda_codec *codec)
 {
 	struct ca0110_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
-	static char *prefix[AUTO_CFG_MAX_OUTS] = {
+	static const char * const prefix[AUTO_CFG_MAX_OUTS] = {
 		"Front", "Surround", NULL, "Side", "Multi"
 	};
 	hda_nid_t mutenid;
@@ -259,7 +259,7 @@ static int ca0110_build_controls(struct hda_codec *codec)
 
 /*
  */
-static struct hda_pcm_stream ca0110_pcm_analog_playback = {
+static const struct hda_pcm_stream ca0110_pcm_analog_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 8,
@@ -270,7 +270,7 @@ static struct hda_pcm_stream ca0110_pcm_analog_playback = {
 	},
 };
 
-static struct hda_pcm_stream ca0110_pcm_analog_capture = {
+static const struct hda_pcm_stream ca0110_pcm_analog_capture = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -280,7 +280,7 @@ static struct hda_pcm_stream ca0110_pcm_analog_capture = {
 	},
 };
 
-static struct hda_pcm_stream ca0110_pcm_digital_playback = {
+static const struct hda_pcm_stream ca0110_pcm_digital_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -291,7 +291,7 @@ static struct hda_pcm_stream ca0110_pcm_digital_playback = {
 	},
 };
 
-static struct hda_pcm_stream ca0110_pcm_digital_capture = {
+static const struct hda_pcm_stream ca0110_pcm_digital_capture = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -389,7 +389,7 @@ static void ca0110_free(struct hda_codec *codec)
 	kfree(codec->spec);
 }
 
-static struct hda_codec_ops ca0110_patch_ops = {
+static const struct hda_codec_ops ca0110_patch_ops = {
 	.build_controls = ca0110_build_controls,
 	.build_pcms = ca0110_build_pcms,
 	.init = ca0110_init,
@@ -539,7 +539,7 @@ static int patch_ca0110(struct hda_codec *codec)
 /*
  * patch entries
  */
-static struct hda_codec_preset snd_hda_preset_ca0110[] = {
+static const struct hda_codec_preset snd_hda_preset_ca0110[] = {
 	{ .id = 0x1102000a, .name = "CA0110-IBG", .patch = patch_ca0110 },
 	{ .id = 0x1102000b, .name = "CA0110-IBG", .patch = patch_ca0110 },
 	{ .id = 0x1102000d, .name = "SB0880 X-Fi", .patch = patch_ca0110 },
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 067982f4f182..26a1521045bb 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -51,7 +51,7 @@ struct cs_spec {
 	unsigned int cur_adc_format;
 	hda_nid_t dig_in;
 
-	struct hda_bind_ctls *capture_bind[2];
+	const struct hda_bind_ctls *capture_bind[2];
 
 	unsigned int gpio_mask;
 	unsigned int gpio_dir;
@@ -231,7 +231,7 @@ static int cs_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 
 /*
  */
-static struct hda_pcm_stream cs_pcm_analog_playback = {
+static const struct hda_pcm_stream cs_pcm_analog_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -242,7 +242,7 @@ static struct hda_pcm_stream cs_pcm_analog_playback = {
 	},
 };
 
-static struct hda_pcm_stream cs_pcm_analog_capture = {
+static const struct hda_pcm_stream cs_pcm_analog_capture = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -252,7 +252,7 @@ static struct hda_pcm_stream cs_pcm_analog_capture = {
 	},
 };
 
-static struct hda_pcm_stream cs_pcm_digital_playback = {
+static const struct hda_pcm_stream cs_pcm_digital_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -264,7 +264,7 @@ static struct hda_pcm_stream cs_pcm_digital_playback = {
 	},
 };
 
-static struct hda_pcm_stream cs_pcm_digital_capture = {
+static const struct hda_pcm_stream cs_pcm_digital_capture = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -331,8 +331,8 @@ static int is_ext_mic(struct hda_codec *codec, unsigned int idx)
 	struct cs_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
 	hda_nid_t pin = cfg->inputs[idx].pin;
-	unsigned int val = snd_hda_query_pin_caps(codec, pin);
-	if (!(val & AC_PINCAP_PRES_DETECT))
+	unsigned int val;
+	if (!is_jack_detectable(codec, pin))
 		return 0;
 	val = snd_hda_codec_get_pincfg(codec, pin);
 	return (snd_hda_get_input_pin_attr(val) != INPUT_PIN_ATTR_INT);
@@ -349,8 +349,7 @@ static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin,
 		hda_nid_t pins[2];
 		unsigned int type;
 		int j, nums;
-		type = (get_wcaps(codec, nid) & AC_WCAP_TYPE)
-			>> AC_WCAP_TYPE_SHIFT;
+		type = get_wcaps_type(get_wcaps(codec, nid));
 		if (type != AC_WID_AUD_IN)
 			continue;
 		nums = snd_hda_get_connections(codec, nid, pins,
@@ -559,10 +558,10 @@ static int add_output(struct hda_codec *codec, hda_nid_t dac, int idx,
 	const char *name;
 	int err, index;
 	struct snd_kcontrol *kctl;
-	static char *speakers[] = {
+	static const char * const speakers[] = {
 		"Front Speaker", "Surround Speaker", "Bass Speaker"
 	};
-	static char *line_outs[] = {
+	static const char * const line_outs[] = {
 		"Front Line-Out", "Surround Line-Out", "Bass Line-Out"
 	};
 
@@ -642,7 +641,7 @@ static int build_output(struct hda_codec *codec)
 /*
  */
 
-static struct snd_kcontrol_new cs_capture_ctls[] = {
+static const struct snd_kcontrol_new cs_capture_ctls[] = {
 	HDA_BIND_SW("Capture Switch", 0),
 	HDA_BIND_VOL("Capture Volume", 0),
 };
@@ -710,7 +709,7 @@ static int cs_capture_source_put(struct snd_kcontrol *kcontrol,
 	return change_cur_input(codec, idx, 0);
 }
 
-static struct snd_kcontrol_new cs_capture_source = {
+static const struct snd_kcontrol_new cs_capture_source = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Capture Source",
 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
@@ -719,7 +718,7 @@ static struct snd_kcontrol_new cs_capture_source = {
 	.put = cs_capture_source_put,
 };
 
-static struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec,
+static const struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec,
 					       struct hda_ctl_ops *ops)
 {
 	struct cs_spec *spec = codec->spec;
@@ -847,15 +846,14 @@ static void cs_automute(struct hda_codec *codec)
 {
 	struct cs_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
-	unsigned int caps, hp_present;
+	unsigned int hp_present;
 	hda_nid_t nid;
 	int i;
 
 	hp_present = 0;
 	for (i = 0; i < cfg->hp_outs; i++) {
 		nid = cfg->hp_pins[i];
-		caps = snd_hda_query_pin_caps(codec, nid);
-		if (!(caps & AC_PINCAP_PRES_DETECT))
+		if (!is_jack_detectable(codec, nid))
 			continue;
 		hp_present = snd_hda_jack_detect(codec, nid);
 		if (hp_present)
@@ -924,7 +922,7 @@ static void init_output(struct hda_codec *codec)
 				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
 		if (!cfg->speaker_outs)
 			continue;
-		if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
+		if (is_jack_detectable(codec, nid)) {
 			snd_hda_codec_write(codec, nid, 0,
 					    AC_VERB_SET_UNSOLICITED_ENABLE,
 					    AC_USRSP_EN | HP_EVENT);
@@ -983,7 +981,7 @@ static void init_input(struct hda_codec *codec)
 	cs_vendor_coef_set(codec, IDX_ADC_CFG, coef);
 }
 
-static struct hda_verb cs_coef_init_verbs[] = {
+static const struct hda_verb cs_coef_init_verbs[] = {
 	{0x11, AC_VERB_SET_PROC_STATE, 1},
 	{0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG},
 	{0x11, AC_VERB_SET_PROC_COEF,
@@ -1017,7 +1015,7 @@ static struct hda_verb cs_coef_init_verbs[] = {
  * blocks, which will alleviate the issue.
  */
 
-static struct hda_verb cs_errata_init_verbs[] = {
+static const struct hda_verb cs_errata_init_verbs[] = {
 	{0x01, AC_VERB_SET_POWER_STATE, 0x00}, /* AFG: D0 */
 	{0x11, AC_VERB_SET_PROC_STATE, 0x01},  /* VPW: processing on */
 
@@ -1126,7 +1124,7 @@ static void cs_unsol_event(struct hda_codec *codec, unsigned int res)
 	}
 }
 
-static struct hda_codec_ops cs_patch_ops = {
+static const struct hda_codec_ops cs_patch_ops = {
 	.build_controls = cs_build_controls,
 	.build_pcms = cs_build_pcms,
 	.init = cs_init,
@@ -1166,7 +1164,7 @@ static const char * const cs420x_models[CS420X_MODELS] = {
 };
 
 
-static struct snd_pci_quirk cs420x_cfg_tbl[] = {
+static const struct snd_pci_quirk cs420x_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
 	SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55),
 	SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
@@ -1180,7 +1178,7 @@ struct cs_pincfg {
 	u32 val;
 };
 
-static struct cs_pincfg mbp53_pincfgs[] = {
+static const struct cs_pincfg mbp53_pincfgs[] = {
 	{ 0x09, 0x012b4050 },
 	{ 0x0a, 0x90100141 },
 	{ 0x0b, 0x90100140 },
@@ -1194,7 +1192,7 @@ static struct cs_pincfg mbp53_pincfgs[] = {
 	{} /* terminator */
 };
 
-static struct cs_pincfg mbp55_pincfgs[] = {
+static const struct cs_pincfg mbp55_pincfgs[] = {
 	{ 0x09, 0x012b4030 },
 	{ 0x0a, 0x90100121 },
 	{ 0x0b, 0x90100120 },
@@ -1208,7 +1206,7 @@ static struct cs_pincfg mbp55_pincfgs[] = {
 	{} /* terminator */
 };
 
-static struct cs_pincfg imac27_pincfgs[] = {
+static const struct cs_pincfg imac27_pincfgs[] = {
 	{ 0x09, 0x012b4050 },
 	{ 0x0a, 0x90100140 },
 	{ 0x0b, 0x90100142 },
@@ -1222,7 +1220,7 @@ static struct cs_pincfg imac27_pincfgs[] = {
 	{} /* terminator */
 };
 
-static struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = {
+static const struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = {
 	[CS420X_MBP53] = mbp53_pincfgs,
 	[CS420X_MBP55] = mbp55_pincfgs,
 	[CS420X_IMAC27] = imac27_pincfgs,
@@ -1283,7 +1281,7 @@ static int patch_cs420x(struct hda_codec *codec)
 /*
  * patch entries
  */
-static struct hda_codec_preset snd_hda_preset_cirrus[] = {
+static const struct hda_codec_preset snd_hda_preset_cirrus[] = {
 	{ .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x },
 	{ .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x },
 	{} /* terminator */
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index 1f8bbcd0f802..ab3308daa960 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -53,7 +53,7 @@ struct cmi_spec {
 	int num_dacs;
 
 	/* capture */
-	hda_nid_t *adc_nids;
+	const hda_nid_t *adc_nids;
 	hda_nid_t dig_in_nid;
 
 	/* capture source */
@@ -110,7 +110,7 @@ static int cmi_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
  */
 
 /* 3-stack / 2 channel */
-static struct hda_verb cmi9880_ch2_init[] = {
+static const struct hda_verb cmi9880_ch2_init[] = {
 	/* set line-in PIN for input */
 	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	/* set mic PIN for input, also enable vref */
@@ -121,7 +121,7 @@ static struct hda_verb cmi9880_ch2_init[] = {
 };
 
 /* 3-stack / 6 channel */
-static struct hda_verb cmi9880_ch6_init[] = {
+static const struct hda_verb cmi9880_ch6_init[] = {
 	/* set line-in PIN for output */
 	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	/* set mic PIN for output */
@@ -132,7 +132,7 @@ static struct hda_verb cmi9880_ch6_init[] = {
 };
 
 /* 3-stack+front / 8 channel */
-static struct hda_verb cmi9880_ch8_init[] = {
+static const struct hda_verb cmi9880_ch8_init[] = {
 	/* set line-in PIN for output */
 	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	/* set mic PIN for output */
@@ -142,7 +142,7 @@ static struct hda_verb cmi9880_ch8_init[] = {
 	{}
 };
 
-static struct hda_channel_mode cmi9880_channel_modes[3] = {
+static const struct hda_channel_mode cmi9880_channel_modes[3] = {
 	{ 2, cmi9880_ch2_init },
 	{ 6, cmi9880_ch6_init },
 	{ 8, cmi9880_ch8_init },
@@ -174,7 +174,7 @@ static int cmi_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va
 
 /*
  */
-static struct snd_kcontrol_new cmi9880_basic_mixer[] = {
+static const struct snd_kcontrol_new cmi9880_basic_mixer[] = {
 	/* CMI9880 has no playback volumes! */
 	HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), /* front */
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0x0, HDA_OUTPUT),
@@ -205,7 +205,7 @@ static struct snd_kcontrol_new cmi9880_basic_mixer[] = {
 /*
  * shared I/O pins
  */
-static struct snd_kcontrol_new cmi9880_ch_mode_mixer[] = {
+static const struct snd_kcontrol_new cmi9880_ch_mode_mixer[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Channel Mode",
@@ -219,7 +219,7 @@ static struct snd_kcontrol_new cmi9880_ch_mode_mixer[] = {
 /* AUD-in selections:
  * 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x1f 0x20
  */
-static struct hda_input_mux cmi9880_basic_mux = {
+static const struct hda_input_mux cmi9880_basic_mux = {
 	.num_items = 4,
 	.items = {
 		{ "Front Mic", 0x5 },
@@ -229,7 +229,7 @@ static struct hda_input_mux cmi9880_basic_mux = {
 	}
 };
 
-static struct hda_input_mux cmi9880_no_line_mux = {
+static const struct hda_input_mux cmi9880_no_line_mux = {
 	.num_items = 3,
 	.items = {
 		{ "Front Mic", 0x5 },
@@ -239,11 +239,11 @@ static struct hda_input_mux cmi9880_no_line_mux = {
 };
 
 /* front, rear, clfe, rear_surr */
-static hda_nid_t cmi9880_dac_nids[4] = {
+static const hda_nid_t cmi9880_dac_nids[4] = {
 	0x03, 0x04, 0x05, 0x06
 };
 /* ADC0, ADC1 */
-static hda_nid_t cmi9880_adc_nids[2] = {
+static const hda_nid_t cmi9880_adc_nids[2] = {
 	0x08, 0x09
 };
 
@@ -252,7 +252,7 @@ static hda_nid_t cmi9880_adc_nids[2] = {
 
 /*
  */
-static struct hda_verb cmi9880_basic_init[] = {
+static const struct hda_verb cmi9880_basic_init[] = {
 	/* port-D for line out (rear panel) */
 	{ 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
 	/* port-E for HP out (front panel) */
@@ -281,7 +281,7 @@ static struct hda_verb cmi9880_basic_init[] = {
 	{} /* terminator */
 };
 
-static struct hda_verb cmi9880_allout_init[] = {
+static const struct hda_verb cmi9880_allout_init[] = {
 	/* port-D for line out (rear panel) */
 	{ 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
 	/* port-E for HP out (front panel) */
@@ -528,7 +528,7 @@ static int cmi9880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 
 /*
  */
-static struct hda_pcm_stream cmi9880_pcm_analog_playback = {
+static const struct hda_pcm_stream cmi9880_pcm_analog_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 8,
@@ -540,7 +540,7 @@ static struct hda_pcm_stream cmi9880_pcm_analog_playback = {
 	},
 };
 
-static struct hda_pcm_stream cmi9880_pcm_analog_capture = {
+static const struct hda_pcm_stream cmi9880_pcm_analog_capture = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -551,7 +551,7 @@ static struct hda_pcm_stream cmi9880_pcm_analog_capture = {
 	},
 };
 
-static struct hda_pcm_stream cmi9880_pcm_digital_playback = {
+static const struct hda_pcm_stream cmi9880_pcm_digital_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -563,7 +563,7 @@ static struct hda_pcm_stream cmi9880_pcm_digital_playback = {
 	},
 };
 
-static struct hda_pcm_stream cmi9880_pcm_digital_capture = {
+static const struct hda_pcm_stream cmi9880_pcm_digital_capture = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -617,14 +617,14 @@ static const char * const cmi9880_models[CMI_MODELS] = {
 	[CMI_AUTO]	= "auto",
 };
 
-static struct snd_pci_quirk cmi9880_cfg_tbl[] = {
+static const struct snd_pci_quirk cmi9880_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", CMI_FULL_DIG),
 	SND_PCI_QUIRK(0x1854, 0x002b, "LG LS75", CMI_MINIMAL),
 	SND_PCI_QUIRK(0x1854, 0x0032, "LG", CMI_FULL_DIG),
 	{} /* terminator */
 };
 
-static struct hda_codec_ops cmi9880_patch_ops = {
+static const struct hda_codec_ops cmi9880_patch_ops = {
 	.build_controls = cmi9880_build_controls,
 	.build_pcms = cmi9880_build_pcms,
 	.init = cmi9880_init,
@@ -745,7 +745,7 @@ static int patch_cmi9880(struct hda_codec *codec)
 /*
  * patch entries
  */
-static struct hda_codec_preset snd_hda_preset_cmedia[] = {
+static const struct hda_codec_preset snd_hda_preset_cmedia[] = {
 	{ .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 },
  	{ .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 },
 	{} /* terminator */
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index ad97d937d3a8..4f37477d3c71 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -39,6 +39,7 @@
 
 #define CONEXANT_HP_EVENT	0x37
 #define CONEXANT_MIC_EVENT	0x38
+#define CONEXANT_LINE_EVENT	0x39
 
 /* Conexant 5051 specific */
 
@@ -55,9 +56,16 @@ struct pin_dac_pair {
 	int type;
 };
 
+struct imux_info {
+	hda_nid_t pin;		/* input pin NID */
+	hda_nid_t adc;		/* connected ADC NID */	
+	hda_nid_t boost;	/* optional boost volume NID */
+	int index;		/* corresponding to autocfg.input */
+};
+
 struct conexant_spec {
 
-	struct snd_kcontrol_new *mixers[5];
+	const struct snd_kcontrol_new *mixers[5];
 	int num_mixers;
 	hda_nid_t vmaster_nid;
 
@@ -74,14 +82,17 @@ struct conexant_spec {
 					 */
 	unsigned int cur_eapd;
 	unsigned int hp_present;
+	unsigned int line_present;
 	unsigned int auto_mic;
-	int auto_mic_ext;		/* autocfg.inputs[] index for ext mic */
+	int auto_mic_ext;		/* imux_pins[] index for ext mic */
+	int auto_mic_dock;		/* imux_pins[] index for dock mic */
+	int auto_mic_int;		/* imux_pins[] index for int mic */
 	unsigned int need_dac_fix;
 	hda_nid_t slave_dig_outs[2];
 
 	/* capture */
 	unsigned int num_adc_nids;
-	hda_nid_t *adc_nids;
+	const hda_nid_t *adc_nids;
 	hda_nid_t dig_in_nid;		/* digital-in NID; optional */
 
 	unsigned int cur_adc_idx;
@@ -89,9 +100,11 @@ struct conexant_spec {
 	unsigned int cur_adc_stream_tag;
 	unsigned int cur_adc_format;
 
+	const struct hda_pcm_stream *capture_stream;
+
 	/* capture source */
 	const struct hda_input_mux *input_mux;
-	hda_nid_t *capsrc_nids;
+	const hda_nid_t *capsrc_nids;
 	unsigned int cur_mux[3];
 
 	/* channel model */
@@ -106,12 +119,17 @@ struct conexant_spec {
 	/* dynamic controls, init_verbs and input_mux */
 	struct auto_pin_cfg autocfg;
 	struct hda_input_mux private_imux;
+	struct imux_info imux_info[HDA_MAX_NUM_INPUTS];
+	hda_nid_t private_adc_nids[HDA_MAX_NUM_INPUTS];
 	hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 	struct pin_dac_pair dac_info[8];
 	int dac_info_filled;
 
 	unsigned int port_d_mode;
 	unsigned int auto_mute:1;	/* used in auto-parser */
+	unsigned int detect_line:1;	/* Line-out detection enabled */
+	unsigned int automute_lines:1;	/* automute line-out as well */
+	unsigned int automute_hp_lo:1;	/* both HP and LO available */
 	unsigned int dell_automute:1;
 	unsigned int dell_vostro:1;
 	unsigned int ideapad:1;
@@ -119,6 +137,8 @@ struct conexant_spec {
 	unsigned int hp_laptop:1;
 	unsigned int asus:1;
 
+	unsigned int adc_switching:1;
+
 	unsigned int ext_mic_present;
 	unsigned int recording;
 	void (*capture_prepare)(struct hda_codec *codec);
@@ -227,7 +247,7 @@ static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 
 
 
-static struct hda_pcm_stream conexant_pcm_analog_playback = {
+static const struct hda_pcm_stream conexant_pcm_analog_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -239,7 +259,7 @@ static struct hda_pcm_stream conexant_pcm_analog_playback = {
 	},
 };
 
-static struct hda_pcm_stream conexant_pcm_analog_capture = {
+static const struct hda_pcm_stream conexant_pcm_analog_capture = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -251,7 +271,7 @@ static struct hda_pcm_stream conexant_pcm_analog_capture = {
 };
 
 
-static struct hda_pcm_stream conexant_pcm_digital_playback = {
+static const struct hda_pcm_stream conexant_pcm_digital_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -263,7 +283,7 @@ static struct hda_pcm_stream conexant_pcm_digital_playback = {
 	},
 };
 
-static struct hda_pcm_stream conexant_pcm_digital_capture = {
+static const struct hda_pcm_stream conexant_pcm_digital_capture = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -294,7 +314,7 @@ static int cx5051_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 	return 0;
 }
 
-static struct hda_pcm_stream cx5051_pcm_analog_capture = {
+static const struct hda_pcm_stream cx5051_pcm_analog_capture = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -319,13 +339,19 @@ static int conexant_build_pcms(struct hda_codec *codec)
 		spec->multiout.max_channels;
 	info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
 		spec->multiout.dac_nids[0];
-	if (codec->vendor_id == 0x14f15051)
-		info->stream[SNDRV_PCM_STREAM_CAPTURE] =
-			cx5051_pcm_analog_capture;
-	else
-		info->stream[SNDRV_PCM_STREAM_CAPTURE] =
-			conexant_pcm_analog_capture;
-	info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
+	if (spec->capture_stream)
+		info->stream[SNDRV_PCM_STREAM_CAPTURE] = *spec->capture_stream;
+	else {
+		if (codec->vendor_id == 0x14f15051)
+			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+				cx5051_pcm_analog_capture;
+		else {
+			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+				conexant_pcm_analog_capture;
+			info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
+				spec->num_adc_nids;
+		}
+	}
 	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
 
 	if (spec->multiout.dig_out_nid) {
@@ -433,7 +459,7 @@ static void conexant_free(struct hda_codec *codec)
 	kfree(codec->spec);
 }
 
-static struct snd_kcontrol_new cxt_capture_mixers[] = {
+static const struct snd_kcontrol_new cxt_capture_mixers[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Capture Source",
@@ -446,7 +472,7 @@ static struct snd_kcontrol_new cxt_capture_mixers[] = {
 
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 /* additional beep mixers; the actual parameters are overwritten at build */
-static struct snd_kcontrol_new cxt_beep_mixer[] = {
+static const struct snd_kcontrol_new cxt_beep_mixer[] = {
 	HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),
 	{ } /* end */
@@ -456,12 +482,18 @@ static struct snd_kcontrol_new cxt_beep_mixer[] = {
 static const char * const slave_vols[] = {
 	"Headphone Playback Volume",
 	"Speaker Playback Volume",
+	"Front Playback Volume",
+	"Surround Playback Volume",
+	"CLFE Playback Volume",
 	NULL
 };
 
 static const char * const slave_sws[] = {
 	"Headphone Playback Switch",
 	"Speaker Playback Switch",
+	"Front Playback Switch",
+	"Surround Playback Switch",
+	"CLFE Playback Switch",
 	NULL
 };
 
@@ -521,7 +553,7 @@ static int conexant_build_controls(struct hda_codec *codec)
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 	/* create beep controls if needed */
 	if (spec->beep_amp) {
-		struct snd_kcontrol_new *knew;
+		const struct snd_kcontrol_new *knew;
 		for (knew = cxt_beep_mixer; knew->name; knew++) {
 			struct snd_kcontrol *kctl;
 			kctl = snd_ctl_new1(knew, codec);
@@ -546,7 +578,7 @@ static int conexant_suspend(struct hda_codec *codec, pm_message_t state)
 }
 #endif
 
-static struct hda_codec_ops conexant_patch_ops = {
+static const struct hda_codec_ops conexant_patch_ops = {
 	.build_controls = conexant_build_controls,
 	.build_pcms = conexant_build_pcms,
 	.init = conexant_init,
@@ -564,6 +596,7 @@ static struct hda_codec_ops conexant_patch_ops = {
 #define set_beep_amp(spec, nid, idx, dir) /* NOP */
 #endif
 
+static int patch_conexant_auto(struct hda_codec *codec);
 /*
  * EAPD control
  * the private value = nid | (invert << 8)
@@ -662,16 +695,16 @@ static int conexant_ch_mode_put(struct snd_kcontrol *kcontrol,
 
 /* Conexant 5045 specific */
 
-static hda_nid_t cxt5045_dac_nids[1] = { 0x19 };
-static hda_nid_t cxt5045_adc_nids[1] = { 0x1a };
-static hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a };
+static const hda_nid_t cxt5045_dac_nids[1] = { 0x19 };
+static const hda_nid_t cxt5045_adc_nids[1] = { 0x1a };
+static const hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a };
 #define CXT5045_SPDIF_OUT	0x18
 
-static struct hda_channel_mode cxt5045_modes[1] = {
+static const struct hda_channel_mode cxt5045_modes[1] = {
 	{ 2, NULL },
 };
 
-static struct hda_input_mux cxt5045_capture_source = {
+static const struct hda_input_mux cxt5045_capture_source = {
 	.num_items = 2,
 	.items = {
 		{ "IntMic", 0x1 },
@@ -679,7 +712,7 @@ static struct hda_input_mux cxt5045_capture_source = {
 	}
 };
 
-static struct hda_input_mux cxt5045_capture_source_benq = {
+static const struct hda_input_mux cxt5045_capture_source_benq = {
 	.num_items = 5,
 	.items = {
 		{ "IntMic", 0x1 },
@@ -690,7 +723,7 @@ static struct hda_input_mux cxt5045_capture_source_benq = {
 	}
 };
 
-static struct hda_input_mux cxt5045_capture_source_hp530 = {
+static const struct hda_input_mux cxt5045_capture_source_hp530 = {
 	.num_items = 2,
 	.items = {
 		{ "ExtMic", 0x1 },
@@ -723,7 +756,7 @@ static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol,
 }
 
 /* bind volumes of both NID 0x10 and 0x11 */
-static struct hda_bind_ctls cxt5045_hp_bind_master_vol = {
+static const struct hda_bind_ctls cxt5045_hp_bind_master_vol = {
 	.ops = &snd_hda_bind_vol,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT),
@@ -735,12 +768,12 @@ static struct hda_bind_ctls cxt5045_hp_bind_master_vol = {
 /* toggle input of built-in and mic jack appropriately */
 static void cxt5045_hp_automic(struct hda_codec *codec)
 {
-	static struct hda_verb mic_jack_on[] = {
+	static const struct hda_verb mic_jack_on[] = {
 		{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 		{0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
 		{}
 	};
-	static struct hda_verb mic_jack_off[] = {
+	static const struct hda_verb mic_jack_off[] = {
 		{0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 		{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
 		{}
@@ -784,7 +817,7 @@ static void cxt5045_hp_unsol_event(struct hda_codec *codec,
 	}
 }
 
-static struct snd_kcontrol_new cxt5045_mixers[] = {
+static const struct snd_kcontrol_new cxt5045_mixers[] = {
 	HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
 	HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
@@ -808,7 +841,7 @@ static struct snd_kcontrol_new cxt5045_mixers[] = {
 	{}
 };
 
-static struct snd_kcontrol_new cxt5045_benq_mixers[] = {
+static const struct snd_kcontrol_new cxt5045_benq_mixers[] = {
 	HDA_CODEC_VOLUME("CD Capture Volume", 0x1a, 0x04, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Capture Switch", 0x1a, 0x04, HDA_INPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x4, HDA_INPUT),
@@ -825,7 +858,7 @@ static struct snd_kcontrol_new cxt5045_benq_mixers[] = {
 	{}
 };
 
-static struct snd_kcontrol_new cxt5045_mixers_hp530[] = {
+static const struct snd_kcontrol_new cxt5045_mixers_hp530[] = {
 	HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
 	HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
@@ -849,7 +882,7 @@ static struct snd_kcontrol_new cxt5045_mixers_hp530[] = {
 	{}
 };
 
-static struct hda_verb cxt5045_init_verbs[] = {
+static const struct hda_verb cxt5045_init_verbs[] = {
 	/* Line in, Mic */
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
@@ -875,7 +908,7 @@ static struct hda_verb cxt5045_init_verbs[] = {
 	{ } /* end */
 };
 
-static struct hda_verb cxt5045_benq_init_verbs[] = {
+static const struct hda_verb cxt5045_benq_init_verbs[] = {
 	/* Internal Mic, Mic */
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
@@ -901,13 +934,13 @@ static struct hda_verb cxt5045_benq_init_verbs[] = {
 	{ } /* end */
 };
 
-static struct hda_verb cxt5045_hp_sense_init_verbs[] = {
+static const struct hda_verb cxt5045_hp_sense_init_verbs[] = {
 	/* pin sensing on HP jack */
 	{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
 	{ } /* end */
 };
 
-static struct hda_verb cxt5045_mic_sense_init_verbs[] = {
+static const struct hda_verb cxt5045_mic_sense_init_verbs[] = {
 	/* pin sensing on HP jack */
 	{0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
 	{ } /* end */
@@ -917,7 +950,7 @@ static struct hda_verb cxt5045_mic_sense_init_verbs[] = {
 /* Test configuration for debugging, modelled after the ALC260 test
  * configuration.
  */
-static struct hda_input_mux cxt5045_test_capture_source = {
+static const struct hda_input_mux cxt5045_test_capture_source = {
 	.num_items = 5,
 	.items = {
 		{ "MIXER", 0x0 },
@@ -928,7 +961,7 @@ static struct hda_input_mux cxt5045_test_capture_source = {
         },
 };
 
-static struct snd_kcontrol_new cxt5045_test_mixer[] = {
+static const struct snd_kcontrol_new cxt5045_test_mixer[] = {
 
 	/* Output controls */
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT),
@@ -978,7 +1011,7 @@ static struct snd_kcontrol_new cxt5045_test_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb cxt5045_test_init_verbs[] = {
+static const struct hda_verb cxt5045_test_init_verbs[] = {
 	/* Set connections */
 	{ 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
 	{ 0x11, AC_VERB_SET_CONNECT_SEL, 0x0 },
@@ -1047,6 +1080,7 @@ enum {
 #ifdef CONFIG_SND_DEBUG
 	CXT5045_TEST,
 #endif
+	CXT5045_AUTO,
 	CXT5045_MODELS
 };
 
@@ -1059,9 +1093,10 @@ static const char * const cxt5045_models[CXT5045_MODELS] = {
 #ifdef CONFIG_SND_DEBUG
 	[CXT5045_TEST]		= "test",
 #endif
+	[CXT5045_AUTO]			= "auto",
 };
 
-static struct snd_pci_quirk cxt5045_cfg_tbl[] = {
+static const struct snd_pci_quirk cxt5045_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530),
 	SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series",
 			   CXT5045_LAPTOP_HPSENSE),
@@ -1085,6 +1120,16 @@ static int patch_cxt5045(struct hda_codec *codec)
 	struct conexant_spec *spec;
 	int board_config;
 
+	board_config = snd_hda_check_board_config(codec, CXT5045_MODELS,
+						  cxt5045_models,
+						  cxt5045_cfg_tbl);
+#if 0 /* use the old method just for safety */
+	if (board_config < 0)
+		board_config = CXT5045_AUTO;
+#endif
+	if (board_config == CXT5045_AUTO)
+		return patch_conexant_auto(codec);
+
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (!spec)
 		return -ENOMEM;
@@ -1111,9 +1156,6 @@ static int patch_cxt5045(struct hda_codec *codec)
 
 	codec->patch_ops = conexant_patch_ops;
 
-	board_config = snd_hda_check_board_config(codec, CXT5045_MODELS,
-						  cxt5045_models,
-						  cxt5045_cfg_tbl);
 	switch (board_config) {
 	case CXT5045_LAPTOP_HPSENSE:
 		codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
@@ -1196,15 +1238,15 @@ static int patch_cxt5045(struct hda_codec *codec)
 /* Conexant 5047 specific */
 #define CXT5047_SPDIF_OUT	0x11
 
-static hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; /* 0x1c */
-static hda_nid_t cxt5047_adc_nids[1] = { 0x12 };
-static hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a };
+static const hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; /* 0x1c */
+static const hda_nid_t cxt5047_adc_nids[1] = { 0x12 };
+static const hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a };
 
-static struct hda_channel_mode cxt5047_modes[1] = {
+static const struct hda_channel_mode cxt5047_modes[1] = {
 	{ 2, NULL },
 };
 
-static struct hda_input_mux cxt5047_toshiba_capture_source = {
+static const struct hda_input_mux cxt5047_toshiba_capture_source = {
 	.num_items = 2,
 	.items = {
 		{ "ExtMic", 0x2 },
@@ -1256,12 +1298,12 @@ static void cxt5047_hp_automute(struct hda_codec *codec)
 /* toggle input of built-in and mic jack appropriately */
 static void cxt5047_hp_automic(struct hda_codec *codec)
 {
-	static struct hda_verb mic_jack_on[] = {
+	static const struct hda_verb mic_jack_on[] = {
 		{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 		{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 		{}
 	};
-	static struct hda_verb mic_jack_off[] = {
+	static const struct hda_verb mic_jack_off[] = {
 		{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 		{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 		{}
@@ -1289,7 +1331,7 @@ static void cxt5047_hp_unsol_event(struct hda_codec *codec,
 	}
 }
 
-static struct snd_kcontrol_new cxt5047_base_mixers[] = {
+static const struct snd_kcontrol_new cxt5047_base_mixers[] = {
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x19, 0x02, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x19, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT),
@@ -1309,19 +1351,19 @@ static struct snd_kcontrol_new cxt5047_base_mixers[] = {
 	{}
 };
 
-static struct snd_kcontrol_new cxt5047_hp_spk_mixers[] = {
+static const struct snd_kcontrol_new cxt5047_hp_spk_mixers[] = {
 	/* See the note in cxt5047_hp_master_sw_put */
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x01, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x13, 0x00, HDA_OUTPUT),
 	{}
 };
 
-static struct snd_kcontrol_new cxt5047_hp_only_mixers[] = {
+static const struct snd_kcontrol_new cxt5047_hp_only_mixers[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT),
 	{ } /* end */
 };
 
-static struct hda_verb cxt5047_init_verbs[] = {
+static const struct hda_verb cxt5047_init_verbs[] = {
 	/* Line in, Mic, Built-in Mic */
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 },
@@ -1348,7 +1390,7 @@ static struct hda_verb cxt5047_init_verbs[] = {
 };
 
 /* configuration for Toshiba Laptops */
-static struct hda_verb cxt5047_toshiba_init_verbs[] = {
+static const struct hda_verb cxt5047_toshiba_init_verbs[] = {
 	{0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0}, /* default off */
 	{}
 };
@@ -1357,7 +1399,7 @@ static struct hda_verb cxt5047_toshiba_init_verbs[] = {
  * configuration.
  */
 #ifdef CONFIG_SND_DEBUG
-static struct hda_input_mux cxt5047_test_capture_source = {
+static const struct hda_input_mux cxt5047_test_capture_source = {
 	.num_items = 4,
 	.items = {
 		{ "LINE1 pin", 0x0 },
@@ -1367,7 +1409,7 @@ static struct hda_input_mux cxt5047_test_capture_source = {
         },
 };
 
-static struct snd_kcontrol_new cxt5047_test_mixer[] = {
+static const struct snd_kcontrol_new cxt5047_test_mixer[] = {
 
 	/* Output only controls */
 	HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x0, HDA_OUTPUT),
@@ -1420,7 +1462,7 @@ static struct snd_kcontrol_new cxt5047_test_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb cxt5047_test_init_verbs[] = {
+static const struct hda_verb cxt5047_test_init_verbs[] = {
 	/* Enable retasking pins as output, initially without power amp */
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
@@ -1492,6 +1534,7 @@ enum {
 #ifdef CONFIG_SND_DEBUG
 	CXT5047_TEST,
 #endif
+	CXT5047_AUTO,
 	CXT5047_MODELS
 };
 
@@ -1502,9 +1545,10 @@ static const char * const cxt5047_models[CXT5047_MODELS] = {
 #ifdef CONFIG_SND_DEBUG
 	[CXT5047_TEST]		= "test",
 #endif
+	[CXT5047_AUTO]		= "auto",
 };
 
-static struct snd_pci_quirk cxt5047_cfg_tbl[] = {
+static const struct snd_pci_quirk cxt5047_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP),
 	SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series",
 			   CXT5047_LAPTOP),
@@ -1517,6 +1561,16 @@ static int patch_cxt5047(struct hda_codec *codec)
 	struct conexant_spec *spec;
 	int board_config;
 
+	board_config = snd_hda_check_board_config(codec, CXT5047_MODELS,
+						  cxt5047_models,
+						  cxt5047_cfg_tbl);
+#if 0 /* not enabled as default, as BIOS often broken for this codec */
+	if (board_config < 0)
+		board_config = CXT5047_AUTO;
+#endif
+	if (board_config == CXT5047_AUTO)
+		return patch_conexant_auto(codec);
+
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (!spec)
 		return -ENOMEM;
@@ -1540,9 +1594,6 @@ static int patch_cxt5047(struct hda_codec *codec)
 
 	codec->patch_ops = conexant_patch_ops;
 
-	board_config = snd_hda_check_board_config(codec, CXT5047_MODELS,
-						  cxt5047_models,
-						  cxt5047_cfg_tbl);
 	switch (board_config) {
 	case CXT5047_LAPTOP:
 		spec->num_mixers = 2;
@@ -1591,10 +1642,10 @@ static int patch_cxt5047(struct hda_codec *codec)
 }
 
 /* Conexant 5051 specific */
-static hda_nid_t cxt5051_dac_nids[1] = { 0x10 };
-static hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 };
+static const hda_nid_t cxt5051_dac_nids[1] = { 0x10 };
+static const hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 };
 
-static struct hda_channel_mode cxt5051_modes[1] = {
+static const struct hda_channel_mode cxt5051_modes[1] = {
 	{ 2, NULL },
 };
 
@@ -1696,7 +1747,7 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec,
 	snd_hda_input_jack_report(codec, nid);
 }
 
-static struct snd_kcontrol_new cxt5051_playback_mixers[] = {
+static const struct snd_kcontrol_new cxt5051_playback_mixers[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -1709,7 +1760,7 @@ static struct snd_kcontrol_new cxt5051_playback_mixers[] = {
 	{}
 };
 
-static struct snd_kcontrol_new cxt5051_capture_mixers[] = {
+static const struct snd_kcontrol_new cxt5051_capture_mixers[] = {
 	HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT),
@@ -1719,7 +1770,7 @@ static struct snd_kcontrol_new cxt5051_capture_mixers[] = {
 	{}
 };
 
-static struct snd_kcontrol_new cxt5051_hp_mixers[] = {
+static const struct snd_kcontrol_new cxt5051_hp_mixers[] = {
 	HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Volume", 0x15, 0x00, HDA_INPUT),
@@ -1727,19 +1778,19 @@ static struct snd_kcontrol_new cxt5051_hp_mixers[] = {
 	{}
 };
 
-static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = {
+static const struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x14, 0x00, HDA_INPUT),
 	{}
 };
 
-static struct snd_kcontrol_new cxt5051_f700_mixers[] = {
+static const struct snd_kcontrol_new cxt5051_f700_mixers[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x01, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x14, 0x01, HDA_INPUT),
 	{}
 };
 
-static struct snd_kcontrol_new cxt5051_toshiba_mixers[] = {
+static const struct snd_kcontrol_new cxt5051_toshiba_mixers[] = {
 	HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT),
@@ -1747,7 +1798,7 @@ static struct snd_kcontrol_new cxt5051_toshiba_mixers[] = {
 	{}
 };
 
-static struct hda_verb cxt5051_init_verbs[] = {
+static const struct hda_verb cxt5051_init_verbs[] = {
 	/* Line in, Mic */
 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
 	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
@@ -1776,7 +1827,7 @@ static struct hda_verb cxt5051_init_verbs[] = {
 	{ } /* end */
 };
 
-static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = {
+static const struct hda_verb cxt5051_hp_dv6736_init_verbs[] = {
 	/* Line in, Mic */
 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
 	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
@@ -1801,7 +1852,7 @@ static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = {
 	{ } /* end */
 };
 
-static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
+static const struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
 	/* Line in, Mic */
 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
 	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
@@ -1834,7 +1885,7 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
 	{ } /* end */
 };
 
-static struct hda_verb cxt5051_f700_init_verbs[] = {
+static const struct hda_verb cxt5051_f700_init_verbs[] = {
 	/* Line in, Mic */
 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
 	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
@@ -1869,7 +1920,7 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid,
 	snd_hda_input_jack_report(codec, nid);
 }
 
-static struct hda_verb cxt5051_ideapad_init_verbs[] = {
+static const struct hda_verb cxt5051_ideapad_init_verbs[] = {
 	/* Subwoofer */
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -1906,6 +1957,7 @@ enum {
 	CXT5051_F700,       /* HP Compaq Presario F700 */
 	CXT5051_TOSHIBA,	/* Toshiba M300 & co */
 	CXT5051_IDEAPAD,	/* Lenovo IdeaPad Y430 */
+	CXT5051_AUTO,		/* auto-parser */
 	CXT5051_MODELS
 };
 
@@ -1917,9 +1969,10 @@ static const char *const cxt5051_models[CXT5051_MODELS] = {
 	[CXT5051_F700]          = "hp-700",
 	[CXT5051_TOSHIBA]	= "toshiba",
 	[CXT5051_IDEAPAD]	= "ideapad",
+	[CXT5051_AUTO]		= "auto",
 };
 
-static struct snd_pci_quirk cxt5051_cfg_tbl[] = {
+static const struct snd_pci_quirk cxt5051_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736),
 	SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP),
 	SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700),
@@ -1937,6 +1990,16 @@ static int patch_cxt5051(struct hda_codec *codec)
 	struct conexant_spec *spec;
 	int board_config;
 
+	board_config = snd_hda_check_board_config(codec, CXT5051_MODELS,
+						  cxt5051_models,
+						  cxt5051_cfg_tbl);
+#if 0 /* use the old method just for safety */
+	if (board_config < 0)
+		board_config = CXT5051_AUTO;
+#endif
+	if (board_config == CXT5051_AUTO)
+		return patch_conexant_auto(codec);
+
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (!spec)
 		return -ENOMEM;
@@ -1967,9 +2030,6 @@ static int patch_cxt5051(struct hda_codec *codec)
 
 	codec->patch_ops.unsol_event = cxt5051_hp_unsol_event;
 
-	board_config = snd_hda_check_board_config(codec, CXT5051_MODELS,
-						  cxt5051_models,
-						  cxt5051_cfg_tbl);
 	spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC;
 	switch (board_config) {
 	case CXT5051_HP:
@@ -2011,17 +2071,17 @@ static int patch_cxt5051(struct hda_codec *codec)
 
 /* Conexant 5066 specific */
 
-static hda_nid_t cxt5066_dac_nids[1] = { 0x10 };
-static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 };
-static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 };
-static hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 };
+static const hda_nid_t cxt5066_dac_nids[1] = { 0x10 };
+static const hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 };
+static const hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 };
+static const hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 };
 
 /* OLPC's microphone port is DC coupled for use with external sensors,
  * therefore we use a 50% mic bias in order to center the input signal with
  * the DC input range of the codec. */
 #define CXT5066_OLPC_EXT_MIC_BIAS PIN_VREF50
 
-static struct hda_channel_mode cxt5066_modes[1] = {
+static const struct hda_channel_mode cxt5066_modes[1] = {
 	{ 2, NULL },
 };
 
@@ -2176,7 +2236,7 @@ static void cxt5066_vostro_automic(struct hda_codec *codec)
 		{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 		{}
 	};
-	static struct hda_verb ext_mic_absent[] = {
+	static const struct hda_verb ext_mic_absent[] = {
 		/* enable internal mic, port C */
 		{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 
@@ -2209,7 +2269,7 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec)
 		{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 		{}
 	};
-	static struct hda_verb ext_mic_absent[] = {
+	static const struct hda_verb ext_mic_absent[] = {
 		{0x14, AC_VERB_SET_CONNECT_SEL, 2},
 		{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 		{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
@@ -2257,7 +2317,7 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec)
 {
 	unsigned int ext_present, dock_present;
 
-	static struct hda_verb ext_mic_present[] = {
+	static const struct hda_verb ext_mic_present[] = {
 		{0x14, AC_VERB_SET_CONNECT_SEL, 0},
 		{0x17, AC_VERB_SET_CONNECT_SEL, 1},
 		{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
@@ -2265,7 +2325,7 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec)
 		{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 		{}
 	};
-	static struct hda_verb dock_mic_present[] = {
+	static const struct hda_verb dock_mic_present[] = {
 		{0x14, AC_VERB_SET_CONNECT_SEL, 0},
 		{0x17, AC_VERB_SET_CONNECT_SEL, 0},
 		{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
@@ -2273,7 +2333,7 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec)
 		{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 		{}
 	};
-	static struct hda_verb ext_mic_absent[] = {
+	static const struct hda_verb ext_mic_absent[] = {
 		{0x14, AC_VERB_SET_CONNECT_SEL, 2},
 		{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 		{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
@@ -2537,7 +2597,7 @@ static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec)
 }
 
 static void conexant_check_dig_outs(struct hda_codec *codec,
-				    hda_nid_t *dig_pins,
+				    const hda_nid_t *dig_pins,
 				    int num_pins)
 {
 	struct conexant_spec *spec = codec->spec;
@@ -2557,7 +2617,7 @@ static void conexant_check_dig_outs(struct hda_codec *codec,
 	}
 }
 
-static struct hda_input_mux cxt5066_capture_source = {
+static const struct hda_input_mux cxt5066_capture_source = {
 	.num_items = 4,
 	.items = {
 		{ "Mic B", 0 },
@@ -2567,7 +2627,7 @@ static struct hda_input_mux cxt5066_capture_source = {
 	},
 };
 
-static struct hda_bind_ctls cxt5066_bind_capture_vol_others = {
+static const struct hda_bind_ctls cxt5066_bind_capture_vol_others = {
 	.ops = &snd_hda_bind_vol,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT),
@@ -2576,7 +2636,7 @@ static struct hda_bind_ctls cxt5066_bind_capture_vol_others = {
 	},
 };
 
-static struct hda_bind_ctls cxt5066_bind_capture_sw_others = {
+static const struct hda_bind_ctls cxt5066_bind_capture_sw_others = {
 	.ops = &snd_hda_bind_sw,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT),
@@ -2585,12 +2645,12 @@ static struct hda_bind_ctls cxt5066_bind_capture_sw_others = {
 	},
 };
 
-static struct snd_kcontrol_new cxt5066_mixer_master[] = {
+static const struct snd_kcontrol_new cxt5066_mixer_master[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
 	{}
 };
 
-static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = {
+static const struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Volume",
@@ -2609,7 +2669,7 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = {
 	{}
 };
 
-static struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = {
+static const struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "DC Mode Enable Switch",
@@ -2627,7 +2687,7 @@ static struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = {
 	{}
 };
 
-static struct snd_kcontrol_new cxt5066_mixers[] = {
+static const struct snd_kcontrol_new cxt5066_mixers[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
@@ -2650,7 +2710,7 @@ static struct snd_kcontrol_new cxt5066_mixers[] = {
 	{}
 };
 
-static struct snd_kcontrol_new cxt5066_vostro_mixers[] = {
+static const struct snd_kcontrol_new cxt5066_vostro_mixers[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Internal Mic Boost Capture Enum",
@@ -2662,7 +2722,7 @@ static struct snd_kcontrol_new cxt5066_vostro_mixers[] = {
 	{}
 };
 
-static struct hda_verb cxt5066_init_verbs[] = {
+static const struct hda_verb cxt5066_init_verbs[] = {
 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */
 	{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */
@@ -2717,7 +2777,7 @@ static struct hda_verb cxt5066_init_verbs[] = {
 	{ } /* end */
 };
 
-static struct hda_verb cxt5066_init_verbs_olpc[] = {
+static const struct hda_verb cxt5066_init_verbs_olpc[] = {
 	/* Port A: headphones */
 	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
@@ -2778,7 +2838,7 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = {
 	{ } /* end */
 };
 
-static struct hda_verb cxt5066_init_verbs_vostro[] = {
+static const struct hda_verb cxt5066_init_verbs_vostro[] = {
 	/* Port A: headphones */
 	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 	{0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
@@ -2839,7 +2899,7 @@ static struct hda_verb cxt5066_init_verbs_vostro[] = {
 	{ } /* end */
 };
 
-static struct hda_verb cxt5066_init_verbs_ideapad[] = {
+static const struct hda_verb cxt5066_init_verbs_ideapad[] = {
 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */
 	{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */
@@ -2889,7 +2949,7 @@ static struct hda_verb cxt5066_init_verbs_ideapad[] = {
 	{ } /* end */
 };
 
-static struct hda_verb cxt5066_init_verbs_thinkpad[] = {
+static const struct hda_verb cxt5066_init_verbs_thinkpad[] = {
 	{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */
 	{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */
 
@@ -2947,13 +3007,13 @@ static struct hda_verb cxt5066_init_verbs_thinkpad[] = {
 	{ } /* end */
 };
 
-static struct hda_verb cxt5066_init_verbs_portd_lo[] = {
+static const struct hda_verb cxt5066_init_verbs_portd_lo[] = {
 	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{ } /* end */
 };
 
 
-static struct hda_verb cxt5066_init_verbs_hp_laptop[] = {
+static const struct hda_verb cxt5066_init_verbs_hp_laptop[] = {
 	{0x14, AC_VERB_SET_CONNECT_SEL, 0x0},
 	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
@@ -2997,6 +3057,7 @@ enum {
 	CXT5066_THINKPAD,	/* Lenovo ThinkPad T410s, others? */
 	CXT5066_ASUS,		/* Asus K52JU, Lenovo G560 - Int mic at 0x1a and Ext mic at 0x1b */
 	CXT5066_HP_LAPTOP,      /* HP Laptop */
+	CXT5066_AUTO,		/* BIOS auto-parser */
 	CXT5066_MODELS
 };
 
@@ -3009,9 +3070,10 @@ static const char * const cxt5066_models[CXT5066_MODELS] = {
 	[CXT5066_THINKPAD]	= "thinkpad",
 	[CXT5066_ASUS]		= "asus",
 	[CXT5066_HP_LAPTOP]	= "hp-laptop",
+	[CXT5066_AUTO]		= "auto",
 };
 
-static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
+static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
 	SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD),
 	SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO),
 	SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD),
@@ -3046,6 +3108,15 @@ static int patch_cxt5066(struct hda_codec *codec)
 	struct conexant_spec *spec;
 	int board_config;
 
+	board_config = snd_hda_check_board_config(codec, CXT5066_MODELS,
+						  cxt5066_models, cxt5066_cfg_tbl);
+#if 0 /* use the old method just for safety */
+	if (board_config < 0)
+		board_config = CXT5066_AUTO;
+#endif
+	if (board_config == CXT5066_AUTO)
+		return patch_conexant_auto(codec);
+
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (!spec)
 		return -ENOMEM;
@@ -3076,8 +3147,6 @@ static int patch_cxt5066(struct hda_codec *codec)
 
 	set_beep_amp(spec, 0x13, 0, HDA_OUTPUT);
 
-	board_config = snd_hda_check_board_config(codec, CXT5066_MODELS,
-						  cxt5066_models, cxt5066_cfg_tbl);
 	switch (board_config) {
 	default:
 	case CXT5066_LAPTOP:
@@ -3195,7 +3264,45 @@ static int patch_cxt5066(struct hda_codec *codec)
  * Automatic parser for CX20641 & co
  */
 
-static hda_nid_t cx_auto_adc_nids[] = { 0x14 };
+static int cx_auto_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+				       struct hda_codec *codec,
+				       unsigned int stream_tag,
+				       unsigned int format,
+				       struct snd_pcm_substream *substream)
+{
+	struct conexant_spec *spec = codec->spec;
+	hda_nid_t adc = spec->imux_info[spec->cur_mux[0]].adc;
+	if (spec->adc_switching) {
+		spec->cur_adc = adc;
+		spec->cur_adc_stream_tag = stream_tag;
+		spec->cur_adc_format = format;
+	}
+	snd_hda_codec_setup_stream(codec, adc, stream_tag, 0, format);
+	return 0;
+}
+
+static int cx_auto_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+				       struct hda_codec *codec,
+				       struct snd_pcm_substream *substream)
+{
+	struct conexant_spec *spec = codec->spec;
+	snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
+	spec->cur_adc = 0;
+	return 0;
+}
+
+static const struct hda_pcm_stream cx_auto_pcm_analog_capture = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0, /* fill later */
+	.ops = {
+		.prepare = cx_auto_capture_pcm_prepare,
+		.cleanup = cx_auto_capture_pcm_cleanup
+	},
+};
+
+static const hda_nid_t cx_auto_adc_nids[] = { 0x14 };
 
 /* get the connection index of @nid in the widget @mux */
 static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
@@ -3320,61 +3427,339 @@ static void cx_auto_parse_output(struct hda_codec *codec)
 	spec->multiout.dac_nids = spec->private_dac_nids;
 	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-	if (cfg->hp_outs > 0)
-		spec->auto_mute = 1;
+	for (i = 0; i < cfg->hp_outs; i++) {
+		if (is_jack_detectable(codec, cfg->hp_pins[i])) {
+			spec->auto_mute = 1;
+			break;
+		}
+	}
+	if (spec->auto_mute && cfg->line_out_pins[0] &&
+	    cfg->line_out_pins[0] != cfg->hp_pins[0] &&
+	    cfg->line_out_pins[0] != cfg->speaker_pins[0]) {
+		for (i = 0; i < cfg->line_outs; i++) {
+			if (is_jack_detectable(codec, cfg->line_out_pins[i])) {
+				spec->detect_line = 1;
+				break;
+			}
+		}
+		spec->automute_lines = spec->detect_line;
+	}
+
 	spec->vmaster_nid = spec->private_dac_nids[0];
 }
 
+static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins,
+			      hda_nid_t *pins, bool on);
+
+static void do_automute(struct hda_codec *codec, int num_pins,
+			hda_nid_t *pins, bool on)
+{
+	int i;
+	for (i = 0; i < num_pins; i++)
+		snd_hda_codec_write(codec, pins[i], 0,
+				    AC_VERB_SET_PIN_WIDGET_CONTROL,
+				    on ? PIN_OUT : 0);
+	cx_auto_turn_eapd(codec, num_pins, pins, on);
+}
+
+static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
+{
+	int i, present = 0;
+
+	for (i = 0; i < num_pins; i++) {
+		hda_nid_t nid = pins[i];
+		if (!nid || !is_jack_detectable(codec, nid))
+			break;
+		snd_hda_input_jack_report(codec, nid);
+		present |= snd_hda_jack_detect(codec, nid);
+	}
+	return present;
+}
+
 /* auto-mute/unmute speaker and line outs according to headphone jack */
+static void cx_auto_update_speakers(struct hda_codec *codec)
+{
+	struct conexant_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int on;
+
+	if (!spec->auto_mute)
+		on = 0;
+	else
+		on = spec->hp_present | spec->line_present;
+	cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on);
+	do_automute(codec, cfg->speaker_outs, cfg->speaker_pins, !on);
+
+	/* toggle line-out mutes if needed, too */
+	/* if LO is a copy of either HP or Speaker, don't need to handle it */
+	if (cfg->line_out_pins[0] == cfg->hp_pins[0] ||
+	    cfg->line_out_pins[0] == cfg->speaker_pins[0])
+		return;
+	if (!spec->automute_lines || !spec->auto_mute)
+		on = 0;
+	else
+		on = spec->hp_present;
+	do_automute(codec, cfg->line_outs, cfg->line_out_pins, !on);
+}
+
 static void cx_auto_hp_automute(struct hda_codec *codec)
 {
 	struct conexant_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
-	int i, present;
 
 	if (!spec->auto_mute)
 		return;
-	present = 0;
-	for (i = 0; i < cfg->hp_outs; i++) {
-		if (snd_hda_jack_detect(codec, cfg->hp_pins[i])) {
-			present = 1;
-			break;
-		}
+	spec->hp_present = detect_jacks(codec, cfg->hp_outs, cfg->hp_pins);
+	cx_auto_update_speakers(codec);
+}
+
+static void cx_auto_line_automute(struct hda_codec *codec)
+{
+	struct conexant_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+
+	if (!spec->auto_mute || !spec->detect_line)
+		return;
+	spec->line_present = detect_jacks(codec, cfg->line_outs,
+					  cfg->line_out_pins);
+	cx_auto_update_speakers(codec);
+}
+
+static int cx_automute_mode_info(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+	static const char * const texts2[] = {
+		"Disabled", "Enabled"
+	};
+	static const char * const texts3[] = {
+		"Disabled", "Speaker Only", "Line-Out+Speaker"
+	};
+	const char * const *texts;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	if (spec->automute_hp_lo) {
+		uinfo->value.enumerated.items = 3;
+		texts = texts3;
+	} else {
+		uinfo->value.enumerated.items = 2;
+		texts = texts2;
 	}
-	for (i = 0; i < cfg->line_outs; i++) {
-		snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL,
-				    present ? 0 : PIN_OUT);
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+	strcpy(uinfo->value.enumerated.name,
+	       texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int cx_automute_mode_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+	unsigned int val;
+	if (!spec->auto_mute)
+		val = 0;
+	else if (!spec->automute_lines)
+		val = 1;
+	else
+		val = 2;
+	ucontrol->value.enumerated.item[0] = val;
+	return 0;
+}
+
+static int cx_automute_mode_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+
+	switch (ucontrol->value.enumerated.item[0]) {
+	case 0:
+		if (!spec->auto_mute)
+			return 0;
+		spec->auto_mute = 0;
+		break;
+	case 1:
+		if (spec->auto_mute && !spec->automute_lines)
+			return 0;
+		spec->auto_mute = 1;
+		spec->automute_lines = 0;
+		break;
+	case 2:
+		if (!spec->automute_hp_lo)
+			return -EINVAL;
+		if (spec->auto_mute && spec->automute_lines)
+			return 0;
+		spec->auto_mute = 1;
+		spec->automute_lines = 1;
+		break;
+	default:
+		return -EINVAL;
 	}
-	for (i = 0; !present && i < cfg->line_outs; i++)
-		if (snd_hda_jack_detect(codec, cfg->line_out_pins[i]))
-			present = 1;
-	for (i = 0; i < cfg->speaker_outs; i++) {
-		snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL,
-				    present ? 0 : PIN_OUT);
+	cx_auto_update_speakers(codec);
+	return 1;
+}
+
+static const struct snd_kcontrol_new cx_automute_mode_enum[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Auto-Mute Mode",
+		.info = cx_automute_mode_info,
+		.get = cx_automute_mode_get,
+		.put = cx_automute_mode_put,
+	},
+	{ }
+};
+
+static int cx_auto_mux_enum_info(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+
+	return snd_hda_input_mux_info(&spec->private_imux, uinfo);
+}
+
+static int cx_auto_mux_enum_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+
+	ucontrol->value.enumerated.item[0] = spec->cur_mux[0];
+	return 0;
+}
+
+/* look for the route the given pin from mux and return the index;
+ * if do_select is set, actually select the route.
+ */
+static int __select_input_connection(struct hda_codec *codec, hda_nid_t mux,
+				     hda_nid_t pin, hda_nid_t *srcp,
+				     bool do_select, int depth)
+{
+	hda_nid_t conn[HDA_MAX_NUM_INPUTS];
+	int i, nums;
+
+	switch (get_wcaps_type(get_wcaps(codec, mux))) {
+	case AC_WID_AUD_IN:
+	case AC_WID_AUD_SEL:
+	case AC_WID_AUD_MIX:
+		break;
+	default:
+		return -1;
 	}
+
+	nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
+	for (i = 0; i < nums; i++)
+		if (conn[i] == pin) {
+			if (do_select)
+				snd_hda_codec_write(codec, mux, 0,
+						    AC_VERB_SET_CONNECT_SEL, i);
+			if (srcp)
+				*srcp = mux;
+			return i;
+		}
+	depth++;
+	if (depth == 2)
+		return -1;
+	for (i = 0; i < nums; i++) {
+		int ret  = __select_input_connection(codec, conn[i], pin, srcp,
+						     do_select, depth);
+		if (ret >= 0) {
+			if (do_select)
+				snd_hda_codec_write(codec, mux, 0,
+						    AC_VERB_SET_CONNECT_SEL, i);
+			return i;
+		}
+	}
+	return -1;
+}
+
+static void select_input_connection(struct hda_codec *codec, hda_nid_t mux,
+				   hda_nid_t pin)
+{
+	__select_input_connection(codec, mux, pin, NULL, true, 0);
+}
+
+static int get_input_connection(struct hda_codec *codec, hda_nid_t mux,
+				hda_nid_t pin)
+{
+	return __select_input_connection(codec, mux, pin, NULL, false, 0);
+}
+
+static int cx_auto_mux_enum_update(struct hda_codec *codec,
+				   const struct hda_input_mux *imux,
+				   unsigned int idx)
+{
+	struct conexant_spec *spec = codec->spec;
+	hda_nid_t adc;
+
+	if (!imux->num_items)
+		return 0;
+	if (idx >= imux->num_items)
+		idx = imux->num_items - 1;
+	if (spec->cur_mux[0] == idx)
+		return 0;
+	adc = spec->imux_info[idx].adc;
+	select_input_connection(codec, spec->imux_info[idx].adc,
+				spec->imux_info[idx].pin);
+	if (spec->cur_adc && spec->cur_adc != adc) {
+		/* stream is running, let's swap the current ADC */
+		__snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
+		spec->cur_adc = adc;
+		snd_hda_codec_setup_stream(codec, adc,
+					   spec->cur_adc_stream_tag, 0,
+					   spec->cur_adc_format);
+	}
+	spec->cur_mux[0] = idx;
+	return 1;
+}
+
+static int cx_auto_mux_enum_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+
+	return cx_auto_mux_enum_update(codec, &spec->private_imux,
+				       ucontrol->value.enumerated.item[0]);
+}
+
+static const struct snd_kcontrol_new cx_auto_capture_mixers[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Source",
+		.info = cx_auto_mux_enum_info,
+		.get = cx_auto_mux_enum_get,
+		.put = cx_auto_mux_enum_put
+	},
+	{}
+};
+
+static bool select_automic(struct hda_codec *codec, int idx, bool detect)
+{
+	struct conexant_spec *spec = codec->spec;
+	if (idx < 0)
+		return false;
+	if (detect && !snd_hda_jack_detect(codec, spec->imux_info[idx].pin))
+		return false;
+	cx_auto_mux_enum_update(codec, &spec->private_imux, idx);
+	return true;
 }
 
 /* automatic switch internal and external mic */
 static void cx_auto_automic(struct hda_codec *codec)
 {
 	struct conexant_spec *spec = codec->spec;
-	struct auto_pin_cfg *cfg = &spec->autocfg;
-	struct hda_input_mux *imux = &spec->private_imux;
-	int ext_idx = spec->auto_mic_ext;
 
 	if (!spec->auto_mic)
 		return;
-	if (snd_hda_jack_detect(codec, cfg->inputs[ext_idx].pin)) {
-		snd_hda_codec_write(codec, spec->adc_nids[0], 0,
-				    AC_VERB_SET_CONNECT_SEL,
-				    imux->items[ext_idx].index);
-	} else {
-		snd_hda_codec_write(codec, spec->adc_nids[0], 0,
-				    AC_VERB_SET_CONNECT_SEL,
-				    imux->items[!ext_idx].index);
-	}
+	if (!select_automic(codec, spec->auto_mic_ext, true))
+		if (!select_automic(codec, spec->auto_mic_dock, true))
+			select_automic(codec, spec->auto_mic_int, false);
 }
 
 static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
@@ -3383,7 +3768,9 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
 	switch (res >> 26) {
 	case CONEXANT_HP_EVENT:
 		cx_auto_hp_automute(codec);
-		snd_hda_input_jack_report(codec, nid);
+		break;
+	case CONEXANT_LINE_EVENT:
+		cx_auto_line_automute(codec);
 		break;
 	case CONEXANT_MIC_EVENT:
 		cx_auto_automic(codec);
@@ -3392,43 +3779,45 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
 	}
 }
 
-/* return true if it's an internal-mic pin */
-static int is_int_mic(struct hda_codec *codec, hda_nid_t pin)
-{
-	unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin);
-	return get_defcfg_device(def_conf) == AC_JACK_MIC_IN &&
-		snd_hda_get_input_pin_attr(def_conf) == INPUT_PIN_ATTR_INT;
-}
-
-/* return true if it's an external-mic pin */
-static int is_ext_mic(struct hda_codec *codec, hda_nid_t pin)
-{
-	unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin);
-	return get_defcfg_device(def_conf) == AC_JACK_MIC_IN &&
-		snd_hda_get_input_pin_attr(def_conf) >= INPUT_PIN_ATTR_NORMAL &&
-		(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_PRES_DETECT);
-}
-
 /* check whether the pin config is suitable for auto-mic switching;
- * auto-mic is enabled only when one int-mic and one-ext mic exist
+ * auto-mic is enabled only when one int-mic and one ext- and/or
+ * one dock-mic exist
  */
 static void cx_auto_check_auto_mic(struct hda_codec *codec)
 {
 	struct conexant_spec *spec = codec->spec;
-	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int pset[INPUT_PIN_ATTR_NORMAL + 1];
+	int i;
 
-	if (is_ext_mic(codec, cfg->inputs[0].pin) &&
-	    is_int_mic(codec, cfg->inputs[1].pin)) {
-		spec->auto_mic = 1;
-		spec->auto_mic_ext = 1;
-		return;
-	}
-	if (is_int_mic(codec, cfg->inputs[1].pin) &&
-	    is_ext_mic(codec, cfg->inputs[0].pin)) {
-		spec->auto_mic = 1;
-		spec->auto_mic_ext = 0;
-		return;
+	for (i = 0; i < INPUT_PIN_ATTR_NORMAL; i++)
+		pset[i] = -1;
+	for (i = 0; i < spec->private_imux.num_items; i++) {
+		hda_nid_t pin = spec->imux_info[i].pin;
+		unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin);
+		int type, attr;
+		attr = snd_hda_get_input_pin_attr(def_conf);
+		if (attr == INPUT_PIN_ATTR_UNUSED)
+			return; /* invalid entry */
+		if (attr > INPUT_PIN_ATTR_NORMAL)
+			attr = INPUT_PIN_ATTR_NORMAL;
+		if (attr != INPUT_PIN_ATTR_INT &&
+		    !is_jack_detectable(codec, pin))
+			return; /* non-detectable pin */
+		type = get_defcfg_device(def_conf);
+		if (type != AC_JACK_MIC_IN &&
+		    (attr != INPUT_PIN_ATTR_DOCK || type != AC_JACK_LINE_IN))
+			return; /* no valid input type */
+		if (pset[attr] >= 0)
+			return; /* already occupied */
+		pset[attr] = i;
 	}
+	if (pset[INPUT_PIN_ATTR_INT] < 0 ||
+	    (pset[INPUT_PIN_ATTR_NORMAL] < 0 && pset[INPUT_PIN_ATTR_DOCK]))
+		return; /* no input to switch*/
+	spec->auto_mic = 1;
+	spec->auto_mic_ext = pset[INPUT_PIN_ATTR_NORMAL];
+	spec->auto_mic_dock = pset[INPUT_PIN_ATTR_DOCK];
+	spec->auto_mic_int = pset[INPUT_PIN_ATTR_INT];
 }
 
 static void cx_auto_parse_input(struct hda_codec *codec)
@@ -3436,22 +3825,37 @@ static void cx_auto_parse_input(struct hda_codec *codec)
 	struct conexant_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
 	struct hda_input_mux *imux;
-	int i;
+	int i, j;
 
 	imux = &spec->private_imux;
 	for (i = 0; i < cfg->num_inputs; i++) {
-		int idx = get_connection_index(codec, spec->adc_nids[0],
-					       cfg->inputs[i].pin);
-		if (idx >= 0) {
-			const char *label;
-			label = hda_get_autocfg_input_label(codec, cfg, i);
-			snd_hda_add_imux_item(imux, label, idx, NULL);
+		for (j = 0; j < spec->num_adc_nids; j++) {
+			hda_nid_t adc = spec->adc_nids[j];
+			int idx = get_input_connection(codec, adc,
+						       cfg->inputs[i].pin);
+			if (idx >= 0) {
+				const char *label;
+				label = hda_get_autocfg_input_label(codec, cfg, i);
+				spec->imux_info[imux->num_items].index = i;
+				spec->imux_info[imux->num_items].boost = 0;
+				spec->imux_info[imux->num_items].adc = adc;
+				spec->imux_info[imux->num_items].pin =
+					cfg->inputs[i].pin;
+				snd_hda_add_imux_item(imux, label, idx, NULL);
+				break;
+			}
 		}
 	}
-	if (imux->num_items == 2 && cfg->num_inputs == 2)
+	if (imux->num_items >= 2 && cfg->num_inputs == imux->num_items)
 		cx_auto_check_auto_mic(codec);
-	if (imux->num_items > 1 && !spec->auto_mic)
-		spec->input_mux = imux;
+	if (imux->num_items > 1 && !spec->auto_mic) {
+		for (i = 1; i < imux->num_items; i++) {
+			if (spec->imux_info[i].adc != spec->imux_info[0].adc) {
+				spec->adc_switching = 1;
+				break;
+			}
+		}
+	}
 }
 
 /* get digital-input audio widget corresponding to the given pin */
@@ -3517,14 +3921,15 @@ static int cx_auto_parse_auto_config(struct hda_codec *codec)
 	return 0;
 }
 
-static void cx_auto_turn_on_eapd(struct hda_codec *codec, int num_pins,
-				 hda_nid_t *pins)
+static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins,
+			      hda_nid_t *pins, bool on)
 {
 	int i;
 	for (i = 0; i < num_pins; i++) {
 		if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD)
 			snd_hda_codec_write(codec, pins[i], 0,
-					    AC_VERB_SET_EAPD_BTLENABLE, 0x02);
+					    AC_VERB_SET_EAPD_BTLENABLE,
+					    on ? 0x02 : 0);
 	}
 }
 
@@ -3537,6 +3942,34 @@ static void select_connection(struct hda_codec *codec, hda_nid_t pin,
 				    AC_VERB_SET_CONNECT_SEL, idx);
 }
 
+static void mute_outputs(struct hda_codec *codec, int num_nids,
+			 const hda_nid_t *nids)
+{
+	int i, val;
+
+	for (i = 0; i < num_nids; i++) {
+		hda_nid_t nid = nids[i];
+		if (!(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
+			continue;
+		if (query_amp_caps(codec, nid, HDA_OUTPUT) & AC_AMPCAP_MUTE)
+			val = AMP_OUT_MUTE;
+		else
+			val = AMP_OUT_ZERO;
+		snd_hda_codec_write(codec, nid, 0,
+				    AC_VERB_SET_AMP_GAIN_MUTE, val);
+	}
+}
+
+static void enable_unsol_pins(struct hda_codec *codec, int num_pins,
+			      hda_nid_t *pins, unsigned int tag)
+{
+	int i;
+	for (i = 0; i < num_pins; i++)
+		snd_hda_codec_write(codec, pins[i], 0,
+				    AC_VERB_SET_UNSOLICITED_ENABLE,
+				    AC_USRSP_EN | tag);
+}
+
 static void cx_auto_init_output(struct hda_codec *codec)
 {
 	struct conexant_spec *spec = codec->spec;
@@ -3544,51 +3977,53 @@ static void cx_auto_init_output(struct hda_codec *codec)
 	hda_nid_t nid;
 	int i;
 
-	for (i = 0; i < spec->multiout.num_dacs; i++)
-		snd_hda_codec_write(codec, spec->multiout.dac_nids[i], 0,
-				    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-
+	mute_outputs(codec, spec->multiout.num_dacs, spec->multiout.dac_nids);
 	for (i = 0; i < cfg->hp_outs; i++)
 		snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
 				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
-	if (spec->auto_mute) {
-		for (i = 0; i < cfg->hp_outs; i++) {
-			snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
-				    AC_VERB_SET_UNSOLICITED_ENABLE,
-				    AC_USRSP_EN | CONEXANT_HP_EVENT);
-		}
-		cx_auto_hp_automute(codec);
-	} else {
-		for (i = 0; i < cfg->line_outs; i++)
-			snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-		for (i = 0; i < cfg->speaker_outs; i++)
-			snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-	}
-
+	mute_outputs(codec, cfg->hp_outs, cfg->hp_pins);
+	mute_outputs(codec, cfg->line_outs, cfg->line_out_pins);
+	mute_outputs(codec, cfg->speaker_outs, cfg->speaker_pins);
 	for (i = 0; i < spec->dac_info_filled; i++) {
 		nid = spec->dac_info[i].dac;
 		if (!nid)
 			nid = spec->multiout.dac_nids[0];
 		select_connection(codec, spec->dac_info[i].pin, nid);
 	}
-
-	/* turn on EAPD */
-	cx_auto_turn_on_eapd(codec, cfg->line_outs, cfg->line_out_pins);
-	cx_auto_turn_on_eapd(codec, cfg->hp_outs, cfg->hp_pins);
-	cx_auto_turn_on_eapd(codec, cfg->speaker_outs, cfg->speaker_pins);
+	if (spec->auto_mute) {
+		enable_unsol_pins(codec, cfg->hp_outs, cfg->hp_pins,
+				  CONEXANT_HP_EVENT);
+		spec->hp_present = detect_jacks(codec, cfg->hp_outs,
+						cfg->hp_pins);
+		if (spec->detect_line) {
+			enable_unsol_pins(codec, cfg->line_outs,
+					  cfg->line_out_pins,
+					  CONEXANT_LINE_EVENT);
+			spec->line_present =
+				detect_jacks(codec, cfg->line_outs,
+					     cfg->line_out_pins);
+		}
+	}
+	cx_auto_update_speakers(codec);
 }
 
 static void cx_auto_init_input(struct hda_codec *codec)
 {
 	struct conexant_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
-	int i;
+	int i, val;
 
-	for (i = 0; i < spec->num_adc_nids; i++)
-		snd_hda_codec_write(codec, spec->adc_nids[i], 0,
-				    AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0));
+	for (i = 0; i < spec->num_adc_nids; i++) {
+		hda_nid_t nid = spec->adc_nids[i];
+		if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP))
+			continue;
+		if (query_amp_caps(codec, nid, HDA_INPUT) & AC_AMPCAP_MUTE)
+			val = AMP_IN_MUTE(0);
+		else
+			val = AMP_IN_UNMUTE(0);
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+				    val);
+	}
 
 	for (i = 0; i < cfg->num_inputs; i++) {
 		unsigned int type;
@@ -3601,17 +4036,22 @@ static void cx_auto_init_input(struct hda_codec *codec)
 	}
 
 	if (spec->auto_mic) {
-		int ext_idx = spec->auto_mic_ext;
-		snd_hda_codec_write(codec, cfg->inputs[ext_idx].pin, 0,
-				    AC_VERB_SET_UNSOLICITED_ENABLE,
-				    AC_USRSP_EN | CONEXANT_MIC_EVENT);
+		if (spec->auto_mic_ext >= 0) {
+			snd_hda_codec_write(codec,
+				cfg->inputs[spec->auto_mic_ext].pin, 0,
+				AC_VERB_SET_UNSOLICITED_ENABLE,
+				AC_USRSP_EN | CONEXANT_MIC_EVENT);
+		}
+		if (spec->auto_mic_dock >= 0) {
+			snd_hda_codec_write(codec,
+				cfg->inputs[spec->auto_mic_dock].pin, 0,
+				AC_VERB_SET_UNSOLICITED_ENABLE,
+				AC_USRSP_EN | CONEXANT_MIC_EVENT);
+		}
 		cx_auto_automic(codec);
 	} else {
-		for (i = 0; i < spec->num_adc_nids; i++) {
-			snd_hda_codec_write(codec, spec->adc_nids[i], 0,
-					    AC_VERB_SET_CONNECT_SEL,
-					    spec->private_imux.items[0].index);
-		}
+		select_input_connection(codec, spec->imux_info[0].adc,
+					spec->imux_info[0].pin);
 	}
 }
 
@@ -3646,7 +4086,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
 		HDA_CODEC_VOLUME(name, 0, 0, 0),
 		HDA_CODEC_MUTE(name, 0, 0, 0),
 	};
-	static char *sfx[2] = { "Volume", "Switch" };
+	static const char * const sfx[2] = { "Volume", "Switch" };
 	int i, err;
 
 	for (i = 0; i < 2; i++) {
@@ -3674,6 +4114,19 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
 #define cx_auto_add_pb_volume(codec, nid, str, idx)			\
 	cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT)
 
+static int try_add_pb_volume(struct hda_codec *codec, hda_nid_t dac,
+			     hda_nid_t pin, const char *name, int idx)
+{
+	unsigned int caps;
+	caps = query_amp_caps(codec, dac, HDA_OUTPUT);
+	if (caps & AC_AMPCAP_NUM_STEPS)
+		return cx_auto_add_pb_volume(codec, dac, name, idx);
+	caps = query_amp_caps(codec, pin, HDA_OUTPUT);
+	if (caps & AC_AMPCAP_NUM_STEPS)
+		return cx_auto_add_pb_volume(codec, pin, name, idx);
+	return 0;
+}
+
 static int cx_auto_build_output_controls(struct hda_codec *codec)
 {
 	struct conexant_spec *spec = codec->spec;
@@ -3682,8 +4135,10 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
 	static const char * const texts[3] = { "Front", "Surround", "CLFE" };
 
 	if (spec->dac_info_filled == 1)
-		return cx_auto_add_pb_volume(codec, spec->dac_info[0].dac,
-					     "Master", 0);
+		return try_add_pb_volume(codec, spec->dac_info[0].dac,
+					 spec->dac_info[0].pin,
+					 "Master", 0);
+
 	for (i = 0; i < spec->dac_info_filled; i++) {
 		const char *label;
 		int idx, type;
@@ -3707,74 +4162,123 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
 			idx = num_spk++;
 			break;
 		}
-		err = cx_auto_add_pb_volume(codec, spec->dac_info[i].dac,
-					    label, idx);
+		err = try_add_pb_volume(codec, spec->dac_info[i].dac,
+					spec->dac_info[i].pin,
+					label, idx);
+		if (err < 0)
+			return err;
+	}
+
+	if (spec->auto_mute) {
+		err = snd_hda_add_new_ctls(codec, cx_automute_mode_enum);
 		if (err < 0)
 			return err;
 	}
+	
+	return 0;
+}
+
+static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
+				      const char *label, const char *pfx,
+				      int cidx)
+{
+	struct conexant_spec *spec = codec->spec;
+	int i;
+
+	for (i = 0; i < spec->num_adc_nids; i++) {
+		hda_nid_t adc_nid = spec->adc_nids[i];
+		int idx = get_input_connection(codec, adc_nid, nid);
+		if (idx < 0)
+			continue;
+		return cx_auto_add_volume_idx(codec, label, pfx,
+					      cidx, adc_nid, HDA_INPUT, idx);
+	}
+	return 0;
+}
+
+static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx,
+				    const char *label, int cidx)
+{
+	struct conexant_spec *spec = codec->spec;
+	hda_nid_t mux, nid;
+	int i, con;
+
+	nid = spec->imux_info[idx].pin;
+	if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
+		return cx_auto_add_volume(codec, label, " Boost", cidx,
+					  nid, HDA_INPUT);
+	con = __select_input_connection(codec, spec->imux_info[idx].adc, nid,
+					&mux, false, 0);
+	if (con < 0)
+		return 0;
+	for (i = 0; i < idx; i++) {
+		if (spec->imux_info[i].boost == mux)
+			return 0; /* already present */
+	}
+
+	if (get_wcaps(codec, mux) & AC_WCAP_OUT_AMP) {
+		spec->imux_info[idx].boost = mux;
+		return cx_auto_add_volume(codec, label, " Boost", 0,
+					  mux, HDA_OUTPUT);
+	}
 	return 0;
 }
 
 static int cx_auto_build_input_controls(struct hda_codec *codec)
 {
 	struct conexant_spec *spec = codec->spec;
-	struct auto_pin_cfg *cfg = &spec->autocfg;
-	static const char *prev_label;
-	int i, err, cidx, conn_len;
-	hda_nid_t conn[HDA_MAX_CONNECTIONS];
-
-	int multi_adc_volume = 0; /* If the ADC nid has several input volumes */
-	int adc_nid = spec->adc_nids[0];
-
-	conn_len = snd_hda_get_connections(codec, adc_nid, conn,
-					   HDA_MAX_CONNECTIONS);
-	if (conn_len < 0)
-		return conn_len;
-
-	multi_adc_volume = cfg->num_inputs > 1 && conn_len > 1;
-	if (!multi_adc_volume) {
-		err = cx_auto_add_volume(codec, "Capture", "", 0, adc_nid,
-					 HDA_INPUT);
-		if (err < 0)
-			return err;
+	struct hda_input_mux *imux = &spec->private_imux;
+	const char *prev_label;
+	int input_conn[HDA_MAX_NUM_INPUTS];
+	int i, err, cidx;
+	int multi_connection;
+
+	multi_connection = 0;
+	for (i = 0; i < imux->num_items; i++) {
+		cidx = get_input_connection(codec, spec->imux_info[i].adc,
+					    spec->imux_info[i].pin);
+		input_conn[i] = (spec->imux_info[i].adc << 8) | cidx;
+		if (i > 0 && input_conn[i] != input_conn[0])
+			multi_connection = 1;
 	}
 
 	prev_label = NULL;
 	cidx = 0;
-	for (i = 0; i < cfg->num_inputs; i++) {
-		hda_nid_t nid = cfg->inputs[i].pin;
+	for (i = 0; i < imux->num_items; i++) {
+		hda_nid_t nid = spec->imux_info[i].pin;
 		const char *label;
-		int j;
-		int pin_amp = get_wcaps(codec, nid) & AC_WCAP_IN_AMP;
-		if (!pin_amp && !multi_adc_volume)
-			continue;
 
-		label = hda_get_autocfg_input_label(codec, cfg, i);
+		label = hda_get_autocfg_input_label(codec, &spec->autocfg,
+						    spec->imux_info[i].index);
 		if (label == prev_label)
 			cidx++;
 		else
 			cidx = 0;
 		prev_label = label;
 
-		if (pin_amp) {
-			err = cx_auto_add_volume(codec, label, " Boost", cidx,
-						 nid, HDA_INPUT);
-			if (err < 0)
-				return err;
-		}
+		err = cx_auto_add_boost_volume(codec, i, label, cidx);
+		if (err < 0)
+			return err;
 
-		if (!multi_adc_volume)
-			continue;
-		for (j = 0; j < conn_len; j++) {
-			if (conn[j] == nid) {
-				err = cx_auto_add_volume_idx(codec, label,
-				    " Capture", cidx, adc_nid, HDA_INPUT, j);
-				if (err < 0)
-					return err;
-				break;
-			}
+		if (!multi_connection) {
+			if (i > 0)
+				continue;
+			err = cx_auto_add_capture_volume(codec, nid,
+							 "Capture", "", cidx);
+		} else {
+			err = cx_auto_add_capture_volume(codec, nid,
+							 label, " Capture", cidx);
 		}
+		if (err < 0)
+			return err;
 	}
+
+	if (spec->private_imux.num_items > 1 && !spec->auto_mic) {
+		err = snd_hda_add_new_ctls(codec, cx_auto_capture_mixers);
+		if (err < 0)
+			return err;
+	}
+
 	return 0;
 }
 
@@ -3791,7 +4295,29 @@ static int cx_auto_build_controls(struct hda_codec *codec)
 	return conexant_build_controls(codec);
 }
 
-static struct hda_codec_ops cx_auto_patch_ops = {
+static int cx_auto_search_adcs(struct hda_codec *codec)
+{
+	struct conexant_spec *spec = codec->spec;
+	hda_nid_t nid, end_nid;
+
+	end_nid = codec->start_nid + codec->num_nodes;
+	for (nid = codec->start_nid; nid < end_nid; nid++) {
+		unsigned int caps = get_wcaps(codec, nid);
+		if (get_wcaps_type(caps) != AC_WID_AUD_IN)
+			continue;
+		if (caps & AC_WCAP_DIGITAL)
+			continue;
+		if (snd_BUG_ON(spec->num_adc_nids >=
+			       ARRAY_SIZE(spec->private_adc_nids)))
+			break;
+		spec->private_adc_nids[spec->num_adc_nids++] = nid;
+	}
+	spec->adc_nids = spec->private_adc_nids;
+	return 0;
+}
+
+
+static const struct hda_codec_ops cx_auto_patch_ops = {
 	.build_controls = cx_auto_build_controls,
 	.build_pcms = conexant_build_pcms,
 	.init = cx_auto_init,
@@ -3808,19 +4334,24 @@ static int patch_conexant_auto(struct hda_codec *codec)
 	struct conexant_spec *spec;
 	int err;
 
+	printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+	       codec->chip_name);
+
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (!spec)
 		return -ENOMEM;
 	codec->spec = spec;
-	spec->adc_nids = cx_auto_adc_nids;
-	spec->num_adc_nids = ARRAY_SIZE(cx_auto_adc_nids);
-	spec->capsrc_nids = spec->adc_nids;
+	codec->pin_amp_workaround = 1;
+	err = cx_auto_search_adcs(codec);
+	if (err < 0)
+		return err;
 	err = cx_auto_parse_auto_config(codec);
 	if (err < 0) {
 		kfree(codec->spec);
 		codec->spec = NULL;
 		return err;
 	}
+	spec->capture_stream = &cx_auto_pcm_analog_capture;
 	codec->patch_ops = cx_auto_patch_ops;
 	if (spec->beep_amp)
 		snd_hda_attach_beep_device(codec, spec->beep_amp);
@@ -3830,7 +4361,7 @@ static int patch_conexant_auto(struct hda_codec *codec)
 /*
  */
 
-static struct hda_codec_preset snd_hda_preset_conexant[] = {
+static const struct hda_codec_preset snd_hda_preset_conexant[] = {
 	{ .id = 0x14f15045, .name = "CX20549 (Venice)",
 	  .patch = patch_cxt5045 },
 	{ .id = 0x14f15047, .name = "CX20551 (Waikiki)",
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 715615a88a8d..322901873222 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -33,6 +33,7 @@
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
+#include <sound/jack.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 
@@ -76,7 +77,7 @@ struct hdmi_spec {
 	 * ati/nvhdmi specific
 	 */
 	struct hda_multi_out multiout;
-	struct hda_pcm_stream *pcm_playback;
+	const struct hda_pcm_stream *pcm_playback;
 
 	/* misc flags */
 	/* PD bit indicates only the update, not the current state */
@@ -720,6 +721,8 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
 				  &spec->sink_eld[index]);
 		/* TODO: do real things about ELD */
 	}
+
+	snd_hda_input_jack_report(codec, tag);
 }
 
 static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
@@ -912,6 +915,7 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
 static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
 {
 	struct hdmi_spec *spec = codec->spec;
+	int err;
 
 	if (spec->num_pins >= MAX_HDMI_PINS) {
 		snd_printk(KERN_WARNING
@@ -919,6 +923,12 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
 		return -E2BIG;
 	}
 
+	err = snd_hda_input_jack_add(codec, pin_nid,
+				     SND_JACK_VIDEOOUT, NULL);
+	if (err < 0)
+		return err;
+	snd_hda_input_jack_report(codec, pin_nid);
+
 	hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]);
 
 	spec->pin[spec->num_pins] = pin_nid;
@@ -1044,7 +1054,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 	return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
 }
 
-static struct hda_pcm_stream generic_hdmi_pcm_playback = {
+static const struct hda_pcm_stream generic_hdmi_pcm_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.ops = {
@@ -1120,11 +1130,12 @@ static void generic_hdmi_free(struct hda_codec *codec)
 
 	for (i = 0; i < spec->num_pins; i++)
 		snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
+	snd_hda_input_jack_free(codec);
 
 	kfree(spec);
 }
 
-static struct hda_codec_ops generic_hdmi_patch_ops = {
+static const struct hda_codec_ops generic_hdmi_patch_ops = {
 	.init			= generic_hdmi_init,
 	.free			= generic_hdmi_free,
 	.build_pcms		= generic_hdmi_build_pcms,
@@ -1169,12 +1180,12 @@ static int patch_generic_hdmi(struct hda_codec *codec)
 #define nvhdmi_master_con_nid_7x	0x04
 #define nvhdmi_master_pin_nid_7x	0x05
 
-static hda_nid_t nvhdmi_con_nids_7x[4] = {
+static const hda_nid_t nvhdmi_con_nids_7x[4] = {
 	/*front, rear, clfe, rear_surr */
 	0x6, 0x8, 0xa, 0xc,
 };
 
-static struct hda_verb nvhdmi_basic_init_7x[] = {
+static const struct hda_verb nvhdmi_basic_init_7x[] = {
 	/* set audio protect on */
 	{ 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
 	/* enable digital output on pin widget */
@@ -1435,7 +1446,7 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
 	return 0;
 }
 
-static struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
+static const struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 8,
@@ -1450,7 +1461,7 @@ static struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
 	},
 };
 
-static struct hda_pcm_stream nvhdmi_pcm_playback_2ch = {
+static const struct hda_pcm_stream nvhdmi_pcm_playback_2ch = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -1465,14 +1476,14 @@ static struct hda_pcm_stream nvhdmi_pcm_playback_2ch = {
 	},
 };
 
-static struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = {
+static const struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = {
 	.build_controls = generic_hdmi_build_controls,
 	.build_pcms = generic_hdmi_build_pcms,
 	.init = nvhdmi_7x_init,
 	.free = generic_hdmi_free,
 };
 
-static struct hda_codec_ops nvhdmi_patch_ops_2ch = {
+static const struct hda_codec_ops nvhdmi_patch_ops_2ch = {
 	.build_controls = generic_hdmi_build_controls,
 	.build_pcms = generic_hdmi_build_pcms,
 	.init = nvhdmi_7x_init,
@@ -1568,7 +1579,7 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 	return 0;
 }
 
-static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
+static const struct hda_pcm_stream atihdmi_pcm_digital_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -1580,7 +1591,7 @@ static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
 	},
 };
 
-static struct hda_verb atihdmi_basic_init[] = {
+static const struct hda_verb atihdmi_basic_init[] = {
 	/* enable digital output on pin widget */
 	{ 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{} /* terminator */
@@ -1599,7 +1610,7 @@ static int atihdmi_init(struct hda_codec *codec)
 	return 0;
 }
 
-static struct hda_codec_ops atihdmi_patch_ops = {
+static const struct hda_codec_ops atihdmi_patch_ops = {
 	.build_controls = generic_hdmi_build_controls,
 	.build_pcms = generic_hdmi_build_pcms,
 	.init = atihdmi_init,
@@ -1634,7 +1645,7 @@ static int patch_atihdmi(struct hda_codec *codec)
 /*
  * patch entries
  */
-static struct hda_codec_preset snd_hda_preset_hdmi[] = {
+static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
 { .id = 0x1002793c, .name = "RS600 HDMI",	.patch = patch_atihdmi },
 { .id = 0x10027919, .name = "RS600 HDMI",	.patch = patch_atihdmi },
 { .id = 0x1002791a, .name = "RS690/780 HDMI",	.patch = patch_atihdmi },
@@ -1677,6 +1688,7 @@ static struct hda_codec_preset snd_hda_preset_hdmi[] = {
 { .id = 0x80862803, .name = "Eaglelake HDMI",	.patch = patch_generic_hdmi },
 { .id = 0x80862804, .name = "IbexPeak HDMI",	.patch = patch_generic_hdmi },
 { .id = 0x80862805, .name = "CougarPoint HDMI",	.patch = patch_generic_hdmi },
+{ .id = 0x80862806, .name = "PantherPoint HDMI", .patch = patch_generic_hdmi },
 { .id = 0x808629fb, .name = "Crestline HDMI",	.patch = patch_generic_hdmi },
 {} /* terminator */
 };
@@ -1722,6 +1734,7 @@ MODULE_ALIAS("snd-hda-codec-id:80862802");
 MODULE_ALIAS("snd-hda-codec-id:80862803");
 MODULE_ALIAS("snd-hda-codec-id:80862804");
 MODULE_ALIAS("snd-hda-codec-id:80862805");
+MODULE_ALIAS("snd-hda-codec-id:80862806");
 MODULE_ALIAS("snd-hda-codec-id:808629fb");
 
 MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index c82979a8cd09..7a4e10002f56 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -299,11 +299,23 @@ struct alc_customize_define {
 
 struct alc_fixup;
 
+struct alc_multi_io {
+	hda_nid_t pin;		/* multi-io widget pin NID */
+	hda_nid_t dac;		/* DAC to be connected */
+	unsigned int ctl_in;	/* cached input-pin control value */
+};
+
+enum {
+	ALC_AUTOMUTE_PIN,	/* change the pin control */
+	ALC_AUTOMUTE_AMP,	/* mute/unmute the pin AMP */
+	ALC_AUTOMUTE_MIXER,	/* mute/unmute mixer widget AMP */
+};
+
 struct alc_spec {
 	/* codec parameterization */
-	struct snd_kcontrol_new *mixers[5];	/* mixer arrays */
+	const struct snd_kcontrol_new *mixers[5];	/* mixer arrays */
 	unsigned int num_mixers;
-	struct snd_kcontrol_new *cap_mixer;	/* capture mixer */
+	const struct snd_kcontrol_new *cap_mixer;	/* capture mixer */
 	unsigned int beep_amp;	/* beep amp value, set via set_beep_amp() */
 
 	const struct hda_verb *init_verbs[10];	/* initialization verbs
@@ -313,14 +325,14 @@ struct alc_spec {
 	unsigned int num_init_verbs;
 
 	char stream_name_analog[32];	/* analog PCM stream */
-	struct hda_pcm_stream *stream_analog_playback;
-	struct hda_pcm_stream *stream_analog_capture;
-	struct hda_pcm_stream *stream_analog_alt_playback;
-	struct hda_pcm_stream *stream_analog_alt_capture;
+	const struct hda_pcm_stream *stream_analog_playback;
+	const struct hda_pcm_stream *stream_analog_capture;
+	const struct hda_pcm_stream *stream_analog_alt_playback;
+	const struct hda_pcm_stream *stream_analog_alt_capture;
 
 	char stream_name_digital[32];	/* digital PCM stream */
-	struct hda_pcm_stream *stream_digital_playback;
-	struct hda_pcm_stream *stream_digital_capture;
+	const struct hda_pcm_stream *stream_digital_playback;
+	const struct hda_pcm_stream *stream_digital_capture;
 
 	/* playback */
 	struct hda_multi_out multiout;	/* playback set-up
@@ -333,8 +345,8 @@ struct alc_spec {
 
 	/* capture */
 	unsigned int num_adc_nids;
-	hda_nid_t *adc_nids;
-	hda_nid_t *capsrc_nids;
+	const hda_nid_t *adc_nids;
+	const hda_nid_t *capsrc_nids;
 	hda_nid_t dig_in_nid;		/* digital-in NID; optional */
 
 	/* capture setup for dynamic dual-adc switch */
@@ -348,6 +360,7 @@ struct alc_spec {
 	const struct hda_input_mux *input_mux;
 	unsigned int cur_mux[3];
 	struct alc_mic_route ext_mic;
+	struct alc_mic_route dock_mic;
 	struct alc_mic_route int_mic;
 
 	/* channel model */
@@ -375,17 +388,27 @@ struct alc_spec {
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	void (*power_hook)(struct hda_codec *codec);
 #endif
+	void (*shutup)(struct hda_codec *codec);
 
 	/* for pin sensing */
-	unsigned int sense_updated: 1;
 	unsigned int jack_present: 1;
-	unsigned int master_sw: 1;
+	unsigned int line_jack_present:1;
+	unsigned int master_mute:1;
 	unsigned int auto_mic:1;
+	unsigned int automute:1;	/* HP automute enabled */
+	unsigned int detect_line:1;	/* Line-out detection enabled */
+	unsigned int automute_lines:1;	/* automute line-out as well */
+	unsigned int automute_hp_lo:1;	/* both HP and LO available */
 
 	/* other flags */
 	unsigned int no_analog :1; /* digital I/O only */
 	unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
 	unsigned int single_input_src:1;
+
+	/* auto-mute control */
+	int automute_mode;
+	hda_nid_t automute_mixer_nid[AUTO_CFG_MAX_OUTS];
+
 	int init_amp;
 	int codec_variant;	/* flag for other variants */
 
@@ -403,25 +426,29 @@ struct alc_spec {
 	int fixup_id;
 	const struct alc_fixup *fixup_list;
 	const char *fixup_name;
+
+	/* multi-io */
+	int multi_ios;
+	struct alc_multi_io multi_io[4];
 };
 
 /*
  * configuration template - to be copied to the spec instance
  */
 struct alc_config_preset {
-	struct snd_kcontrol_new *mixers[5]; /* should be identical size
+	const struct snd_kcontrol_new *mixers[5]; /* should be identical size
 					     * with spec
 					     */
-	struct snd_kcontrol_new *cap_mixer; /* capture mixer */
+	const struct snd_kcontrol_new *cap_mixer; /* capture mixer */
 	const struct hda_verb *init_verbs[5];
 	unsigned int num_dacs;
-	hda_nid_t *dac_nids;
+	const hda_nid_t *dac_nids;
 	hda_nid_t dig_out_nid;		/* optional */
 	hda_nid_t hp_nid;		/* optional */
-	hda_nid_t *slave_dig_outs;
+	const hda_nid_t *slave_dig_outs;
 	unsigned int num_adc_nids;
-	hda_nid_t *adc_nids;
-	hda_nid_t *capsrc_nids;
+	const hda_nid_t *adc_nids;
+	const hda_nid_t *capsrc_nids;
 	hda_nid_t dig_in_nid;
 	unsigned int num_channel_mode;
 	const struct hda_channel_mode *channel_mode;
@@ -433,7 +460,7 @@ struct alc_config_preset {
 	void (*setup)(struct hda_codec *);
 	void (*init_hook)(struct hda_codec *);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-	struct hda_amp_list *loopbacks;
+	const struct hda_amp_list *loopbacks;
 	void (*power_hook)(struct hda_codec *codec);
 #endif
 };
@@ -560,11 +587,11 @@ static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
  * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
  * March 2006.
  */
-static char *alc_pin_mode_names[] = {
+static const char * const alc_pin_mode_names[] = {
 	"Mic 50pc bias", "Mic 80pc bias",
 	"Line in", "Line out", "Headphone out",
 };
-static unsigned char alc_pin_mode_values[] = {
+static const unsigned char alc_pin_mode_values[] = {
 	PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
 };
 /* The control can present all 5 options, or it can limit the options based
@@ -583,7 +610,7 @@ static unsigned char alc_pin_mode_values[] = {
 /* Info about the pin modes supported by the different pin direction modes.
  * For each direction the minimum and maximum values are given.
  */
-static signed char alc_pin_mode_dir_info[5][2] = {
+static const signed char alc_pin_mode_dir_info[5][2] = {
 	{ 0, 2 },    /* ALC_PIN_DIR_IN */
 	{ 3, 4 },    /* ALC_PIN_DIR_OUT */
 	{ 0, 4 },    /* ALC_PIN_DIR_INOUT */
@@ -900,7 +927,7 @@ static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec)
 
 /*
  */
-static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
+static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix)
 {
 	if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
 		return;
@@ -971,21 +998,21 @@ static void setup_preset(struct hda_codec *codec,
 }
 
 /* Enable GPIO mask and set output */
-static struct hda_verb alc_gpio1_init_verbs[] = {
+static const struct hda_verb alc_gpio1_init_verbs[] = {
 	{0x01, AC_VERB_SET_GPIO_MASK, 0x01},
 	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
 	{0x01, AC_VERB_SET_GPIO_DATA, 0x01},
 	{ }
 };
 
-static struct hda_verb alc_gpio2_init_verbs[] = {
+static const struct hda_verb alc_gpio2_init_verbs[] = {
 	{0x01, AC_VERB_SET_GPIO_MASK, 0x02},
 	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
 	{0x01, AC_VERB_SET_GPIO_DATA, 0x02},
 	{ }
 };
 
-static struct hda_verb alc_gpio3_init_verbs[] = {
+static const struct hda_verb alc_gpio3_init_verbs[] = {
 	{0x01, AC_VERB_SET_GPIO_MASK, 0x03},
 	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
 	{0x01, AC_VERB_SET_GPIO_DATA, 0x03},
@@ -1031,6 +1058,7 @@ static int alc_init_jacks(struct hda_codec *codec)
 	int err;
 	unsigned int hp_nid = spec->autocfg.hp_pins[0];
 	unsigned int mic_nid = spec->ext_mic.pin;
+	unsigned int dock_nid = spec->dock_mic.pin;
 
 	if (hp_nid) {
 		err = snd_hda_input_jack_add(codec, hp_nid,
@@ -1047,46 +1075,116 @@ static int alc_init_jacks(struct hda_codec *codec)
 			return err;
 		snd_hda_input_jack_report(codec, mic_nid);
 	}
+	if (dock_nid) {
+		err = snd_hda_input_jack_add(codec, dock_nid,
+					     SND_JACK_MICROPHONE, NULL);
+		if (err < 0)
+			return err;
+		snd_hda_input_jack_report(codec, dock_nid);
+	}
 #endif /* CONFIG_SND_HDA_INPUT_JACK */
 	return 0;
 }
 
-static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
+static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
 {
-	struct alc_spec *spec = codec->spec;
-	unsigned int mute;
-	hda_nid_t nid;
-	int i;
+	int i, present = 0;
 
-	spec->jack_present = 0;
-	for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
-		nid = spec->autocfg.hp_pins[i];
+	for (i = 0; i < num_pins; i++) {
+		hda_nid_t nid = pins[i];
 		if (!nid)
 			break;
 		snd_hda_input_jack_report(codec, nid);
-		spec->jack_present |= snd_hda_jack_detect(codec, nid);
+		present |= snd_hda_jack_detect(codec, nid);
 	}
+	return present;
+}
+
+static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
+			bool mute, bool hp_out)
+{
+	struct alc_spec *spec = codec->spec;
+	unsigned int mute_bits = mute ? HDA_AMP_MUTE : 0;
+	unsigned int pin_bits = mute ? 0 : (hp_out ? PIN_HP : PIN_OUT);
+	int i;
 
-	mute = spec->jack_present ? HDA_AMP_MUTE : 0;
-	/* Toggle internal speakers muting */
-	for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
-		nid = spec->autocfg.speaker_pins[i];
+	for (i = 0; i < num_pins; i++) {
+		hda_nid_t nid = pins[i];
 		if (!nid)
 			break;
-		if (pinctl) {
+		switch (spec->automute_mode) {
+		case ALC_AUTOMUTE_PIN:
 			snd_hda_codec_write(codec, nid, 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL,
-				    spec->jack_present ? 0 : PIN_OUT);
-		} else {
+					    AC_VERB_SET_PIN_WIDGET_CONTROL,
+					    pin_bits);
+			break;
+		case ALC_AUTOMUTE_AMP:
 			snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
+						 HDA_AMP_MUTE, mute_bits);
+			break;
+		case ALC_AUTOMUTE_MIXER:
+			nid = spec->automute_mixer_nid[i];
+			if (!nid)
+				break;
+			snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
+						 HDA_AMP_MUTE, mute_bits);
+			snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 1,
+						 HDA_AMP_MUTE, mute_bits);
+			break;
 		}
 	}
 }
 
-static void alc_automute_pin(struct hda_codec *codec)
+/* Toggle internal speakers muting */
+static void update_speakers(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	int on;
+
+	if (!spec->automute)
+		on = 0;
+	else
+		on = spec->jack_present | spec->line_jack_present;
+	on |= spec->master_mute;
+	do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
+		    spec->autocfg.speaker_pins, on, false);
+
+	/* toggle line-out mutes if needed, too */
+	/* if LO is a copy of either HP or Speaker, don't need to handle it */
+	if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
+	    spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
+		return;
+	if (!spec->automute_lines || !spec->automute)
+		on = 0;
+	else
+		on = spec->jack_present;
+	on |= spec->master_mute;
+	do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
+		    spec->autocfg.line_out_pins, on, false);
+}
+
+static void alc_hp_automute(struct hda_codec *codec)
 {
-	alc_automute_speaker(codec, 1);
+	struct alc_spec *spec = codec->spec;
+
+	if (!spec->automute)
+		return;
+	spec->jack_present =
+		detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
+			     spec->autocfg.hp_pins);
+	update_speakers(codec);
+}
+
+static void alc_line_automute(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	if (!spec->automute || !spec->detect_line)
+		return;
+	spec->line_jack_present =
+		detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
+			     spec->autocfg.line_out_pins);
+	update_speakers(codec);
 }
 
 static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
@@ -1128,7 +1226,7 @@ static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec)
 static void alc_mic_automute(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
-	struct alc_mic_route *dead, *alive;
+	struct alc_mic_route *dead1, *dead2, *alive;
 	unsigned int present, type;
 	hda_nid_t cap_nid;
 
@@ -1146,13 +1244,24 @@ static void alc_mic_automute(struct hda_codec *codec)
 
 	cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
 
+	alive = &spec->int_mic;
+	dead1 = &spec->ext_mic;
+	dead2 = &spec->dock_mic;
+
 	present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
 	if (present) {
 		alive = &spec->ext_mic;
-		dead = &spec->int_mic;
-	} else {
-		alive = &spec->int_mic;
-		dead = &spec->ext_mic;
+		dead1 = &spec->int_mic;
+		dead2 = &spec->dock_mic;
+	}
+	if (!present && spec->dock_mic.pin > 0) {
+		present = snd_hda_jack_detect(codec, spec->dock_mic.pin);
+		if (present) {
+			alive = &spec->dock_mic;
+			dead1 = &spec->int_mic;
+			dead2 = &spec->ext_mic;
+		}
+		snd_hda_input_jack_report(codec, spec->dock_mic.pin);
 	}
 
 	type = get_wcaps_type(get_wcaps(codec, cap_nid));
@@ -1161,9 +1270,14 @@ static void alc_mic_automute(struct hda_codec *codec)
 		snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
 					 alive->mux_idx,
 					 HDA_AMP_MUTE, 0);
-		snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
-					 dead->mux_idx,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
+		if (dead1->pin > 0)
+			snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
+						 dead1->mux_idx,
+						 HDA_AMP_MUTE, HDA_AMP_MUTE);
+		if (dead2->pin > 0)
+			snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
+						 dead2->mux_idx,
+						 HDA_AMP_MUTE, HDA_AMP_MUTE);
 	} else {
 		/* MUX style (e.g. ALC880) */
 		snd_hda_codec_write_cache(codec, cap_nid, 0,
@@ -1184,7 +1298,10 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
 		res >>= 26;
 	switch (res) {
 	case ALC880_HP_EVENT:
-		alc_automute_pin(codec);
+		alc_hp_automute(codec);
+		break;
+	case ALC880_FRONT_EVENT:
+		alc_line_automute(codec);
 		break;
 	case ALC880_MIC_EVENT:
 		alc_mic_automute(codec);
@@ -1194,7 +1311,8 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
 
 static void alc_inithook(struct hda_codec *codec)
 {
-	alc_automute_pin(codec);
+	alc_hp_automute(codec);
+	alc_line_automute(codec);
 	alc_mic_automute(codec);
 }
 
@@ -1236,6 +1354,43 @@ static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
 				    on ? 2 : 0);
 }
 
+/* turn on/off EAPD controls of the codec */
+static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
+{
+	/* We currently only handle front, HP */
+	switch (codec->vendor_id) {
+	case 0x10ec0260:
+		set_eapd(codec, 0x0f, on);
+		set_eapd(codec, 0x10, on);
+		break;
+	case 0x10ec0262:
+	case 0x10ec0267:
+	case 0x10ec0268:
+	case 0x10ec0269:
+	case 0x10ec0270:
+	case 0x10ec0272:
+	case 0x10ec0660:
+	case 0x10ec0662:
+	case 0x10ec0663:
+	case 0x10ec0665:
+	case 0x10ec0862:
+	case 0x10ec0889:
+	case 0x10ec0892:
+		set_eapd(codec, 0x14, on);
+		set_eapd(codec, 0x15, on);
+		break;
+	}
+}
+
+/* generic shutup callback;
+ * just turning off EPAD and a little pause for avoiding pop-noise
+ */
+static void alc_eapd_shutup(struct hda_codec *codec)
+{
+	alc_auto_setup_eapd(codec, false);
+	msleep(200);
+}
+
 static void alc_auto_init_amp(struct hda_codec *codec, int type)
 {
 	unsigned int tmp;
@@ -1251,27 +1406,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
 		snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
 		break;
 	case ALC_INIT_DEFAULT:
-		switch (codec->vendor_id) {
-		case 0x10ec0260:
-			set_eapd(codec, 0x0f, 1);
-			set_eapd(codec, 0x10, 1);
-			break;
-		case 0x10ec0262:
-		case 0x10ec0267:
-		case 0x10ec0268:
-		case 0x10ec0269:
-		case 0x10ec0270:
-		case 0x10ec0272:
-		case 0x10ec0660:
-		case 0x10ec0662:
-		case 0x10ec0663:
-		case 0x10ec0665:
-		case 0x10ec0862:
-		case 0x10ec0889:
-			set_eapd(codec, 0x14, 1);
-			set_eapd(codec, 0x15, 1);
-			break;
-		}
+		alc_auto_setup_eapd(codec, true);
 		switch (codec->vendor_id) {
 		case 0x10ec0260:
 			snd_hda_codec_write(codec, 0x1a, 0,
@@ -1315,20 +1450,128 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
 	}
 }
 
+static int alc_automute_mode_info(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	static const char * const texts2[] = {
+		"Disabled", "Enabled"
+	};
+	static const char * const texts3[] = {
+		"Disabled", "Speaker Only", "Line-Out+Speaker"
+	};
+	const char * const *texts;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	if (spec->automute_hp_lo) {
+		uinfo->value.enumerated.items = 3;
+		texts = texts3;
+	} else {
+		uinfo->value.enumerated.items = 2;
+		texts = texts2;
+	}
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+	strcpy(uinfo->value.enumerated.name,
+	       texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int alc_automute_mode_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	unsigned int val;
+	if (!spec->automute)
+		val = 0;
+	else if (!spec->automute_lines)
+		val = 1;
+	else
+		val = 2;
+	ucontrol->value.enumerated.item[0] = val;
+	return 0;
+}
+
+static int alc_automute_mode_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+
+	switch (ucontrol->value.enumerated.item[0]) {
+	case 0:
+		if (!spec->automute)
+			return 0;
+		spec->automute = 0;
+		break;
+	case 1:
+		if (spec->automute && !spec->automute_lines)
+			return 0;
+		spec->automute = 1;
+		spec->automute_lines = 0;
+		break;
+	case 2:
+		if (!spec->automute_hp_lo)
+			return -EINVAL;
+		if (spec->automute && spec->automute_lines)
+			return 0;
+		spec->automute = 1;
+		spec->automute_lines = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+	update_speakers(codec);
+	return 1;
+}
+
+static const struct snd_kcontrol_new alc_automute_mode_enum = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Auto-Mute Mode",
+	.info = alc_automute_mode_info,
+	.get = alc_automute_mode_get,
+	.put = alc_automute_mode_put,
+};
+
+static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec);
+
+static int alc_add_automute_mode_enum(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	struct snd_kcontrol_new *knew;
+
+	knew = alc_kcontrol_new(spec);
+	if (!knew)
+		return -ENOMEM;
+	*knew = alc_automute_mode_enum;
+	knew->name = kstrdup("Auto-Mute Mode", GFP_KERNEL);
+	if (!knew->name)
+		return -ENOMEM;
+	return 0;
+}
+
 static void alc_init_auto_hp(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int present = 0;
 	int i;
 
-	if (!cfg->hp_pins[0]) {
-		if (cfg->line_out_type != AUTO_PIN_HP_OUT)
-			return;
-	}
+	if (cfg->hp_pins[0])
+		present++;
+	if (cfg->line_out_pins[0])
+		present++;
+	if (cfg->speaker_pins[0])
+		present++;
+	if (present < 2) /* need two different output types */
+		return;
+	if (present == 3)
+		spec->automute_hp_lo = 1; /* both HP and LO automute */
 
 	if (!cfg->speaker_pins[0]) {
-		if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
-			return;
 		memcpy(cfg->speaker_pins, cfg->line_out_pins,
 		       sizeof(cfg->speaker_pins));
 		cfg->speaker_outs = cfg->line_outs;
@@ -1341,28 +1584,49 @@ static void alc_init_auto_hp(struct hda_codec *codec)
 	}
 
 	for (i = 0; i < cfg->hp_outs; i++) {
+		hda_nid_t nid = cfg->hp_pins[i];
+		if (!is_jack_detectable(codec, nid))
+			continue;
 		snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
-			    cfg->hp_pins[i]);
-		snd_hda_codec_write_cache(codec, cfg->hp_pins[i], 0,
+			    nid);
+		snd_hda_codec_write_cache(codec, nid, 0,
 				  AC_VERB_SET_UNSOLICITED_ENABLE,
 				  AC_USRSP_EN | ALC880_HP_EVENT);
+		spec->automute = 1;
+		spec->automute_mode = ALC_AUTOMUTE_PIN;
+	}
+	if (spec->automute && cfg->line_out_pins[0] &&
+	    cfg->line_out_pins[0] != cfg->hp_pins[0] &&
+	    cfg->line_out_pins[0] != cfg->speaker_pins[0]) {
+		for (i = 0; i < cfg->line_outs; i++) {
+			hda_nid_t nid = cfg->line_out_pins[i];
+			if (!is_jack_detectable(codec, nid))
+				continue;
+			snd_printdd("realtek: Enable Line-Out auto-muting "
+				    "on NID 0x%x\n", nid);
+			snd_hda_codec_write_cache(codec, nid, 0,
+					AC_VERB_SET_UNSOLICITED_ENABLE,
+					AC_USRSP_EN | ALC880_FRONT_EVENT);
+			spec->detect_line = 1;
+		}
+		spec->automute_lines = spec->detect_line;
+	}
+
+	if (spec->automute) {
+		/* create a control for automute mode */
+		alc_add_automute_mode_enum(codec);
+		spec->unsol_event = alc_sku_unsol_event;
 	}
-	spec->unsol_event = alc_sku_unsol_event;
 }
 
 static void alc_init_auto_mic(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
-	hda_nid_t fixed, ext;
+	hda_nid_t fixed, ext, dock;
 	int i;
 
-	/* there must be only two mic inputs exclusively */
-	for (i = 0; i < cfg->num_inputs; i++)
-		if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN)
-			return;
-
-	fixed = ext = 0;
+	fixed = ext = dock = 0;
 	for (i = 0; i < cfg->num_inputs; i++) {
 		hda_nid_t nid = cfg->inputs[i].pin;
 		unsigned int defcfg;
@@ -1371,26 +1635,45 @@ static void alc_init_auto_mic(struct hda_codec *codec)
 		case INPUT_PIN_ATTR_INT:
 			if (fixed)
 				return; /* already occupied */
+			if (cfg->inputs[i].type != AUTO_PIN_MIC)
+				return; /* invalid type */
 			fixed = nid;
 			break;
 		case INPUT_PIN_ATTR_UNUSED:
 			return; /* invalid entry */
+		case INPUT_PIN_ATTR_DOCK:
+			if (dock)
+				return; /* already occupied */
+			if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
+				return; /* invalid type */
+			dock = nid;
+			break;
 		default:
 			if (ext)
 				return; /* already occupied */
+			if (cfg->inputs[i].type != AUTO_PIN_MIC)
+				return; /* invalid type */
 			ext = nid;
 			break;
 		}
 	}
+	if (!ext && dock) {
+		ext = dock;
+		dock = 0;
+	}
 	if (!ext || !fixed)
 		return;
-	if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
+	if (!is_jack_detectable(codec, ext))
+		return; /* no unsol support */
+	if (dock && !is_jack_detectable(codec, dock))
 		return; /* no unsol support */
-	snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x\n",
-		    ext, fixed);
+	snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
+		    ext, fixed, dock);
 	spec->ext_mic.pin = ext;
+	spec->dock_mic.pin = dock;
 	spec->int_mic.pin = fixed;
 	spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
+	spec->dock_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
 	spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
 	spec->auto_mic = 1;
 	snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0,
@@ -1583,9 +1866,6 @@ do_sku:
 				return 1;
 		spec->autocfg.hp_pins[0] = nid;
 	}
-
-	alc_init_auto_hp(codec);
-	alc_init_auto_mic(codec);
 	return 1;
 }
 
@@ -1598,9 +1878,10 @@ static void alc_ssid_check(struct hda_codec *codec,
 		snd_printd("realtek: "
 			   "Enable default setup for auto mode as fallback\n");
 		spec->init_amp = ALC_INIT_DEFAULT;
-		alc_init_auto_hp(codec);
-		alc_init_auto_mic(codec);
 	}
+
+	alc_init_auto_hp(codec);
+	alc_init_auto_mic(codec);
 }
 
 /*
@@ -1842,7 +2123,7 @@ static void alc_auto_parse_digital(struct hda_codec *codec)
 /*
  * 2ch mode
  */
-static struct hda_verb alc888_4ST_ch2_intel_init[] = {
+static const struct hda_verb alc888_4ST_ch2_intel_init[] = {
 /* Mic-in jack as mic in */
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
@@ -1857,7 +2138,7 @@ static struct hda_verb alc888_4ST_ch2_intel_init[] = {
 /*
  * 4ch mode
  */
-static struct hda_verb alc888_4ST_ch4_intel_init[] = {
+static const struct hda_verb alc888_4ST_ch4_intel_init[] = {
 /* Mic-in jack as mic in */
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
@@ -1872,7 +2153,7 @@ static struct hda_verb alc888_4ST_ch4_intel_init[] = {
 /*
  * 6ch mode
  */
-static struct hda_verb alc888_4ST_ch6_intel_init[] = {
+static const struct hda_verb alc888_4ST_ch6_intel_init[] = {
 /* Mic-in jack as CLFE */
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
@@ -1887,7 +2168,7 @@ static struct hda_verb alc888_4ST_ch6_intel_init[] = {
 /*
  * 8ch mode
  */
-static struct hda_verb alc888_4ST_ch8_intel_init[] = {
+static const struct hda_verb alc888_4ST_ch8_intel_init[] = {
 /* Mic-in jack as CLFE */
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
@@ -1899,7 +2180,7 @@ static struct hda_verb alc888_4ST_ch8_intel_init[] = {
 	{ } /* end */
 };
 
-static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
+static const struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
 	{ 2, alc888_4ST_ch2_intel_init },
 	{ 4, alc888_4ST_ch4_intel_init },
 	{ 6, alc888_4ST_ch6_intel_init },
@@ -1910,7 +2191,7 @@ static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
  * ALC888 Fujitsu Siemens Amillo xa3530
  */
 
-static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
+static const struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
 /* Front Mic: set to PIN_IN (empty by default) */
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 /* Connect Internal HP to Front */
@@ -1943,22 +2224,6 @@ static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
 	{}
 };
 
-static void alc_automute_amp(struct hda_codec *codec)
-{
-	alc_automute_speaker(codec, 0);
-}
-
-static void alc_automute_amp_unsol_event(struct hda_codec *codec,
-					 unsigned int res)
-{
-	if (codec->vendor_id == 0x10ec0880)
-		res >>= 28;
-	else
-		res >>= 26;
-	if (res == ALC880_HP_EVENT)
-		alc_automute_amp(codec);
-}
-
 static void alc889_automute_setup(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
@@ -1969,12 +2234,14 @@ static void alc889_automute_setup(struct hda_codec *codec)
 	spec->autocfg.speaker_pins[2] = 0x17;
 	spec->autocfg.speaker_pins[3] = 0x19;
 	spec->autocfg.speaker_pins[4] = 0x1a;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 static void alc889_intel_init_hook(struct hda_codec *codec)
 {
 	alc889_coef_init(codec);
-	alc_automute_amp(codec);
+	alc_hp_automute(codec);
 }
 
 static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
@@ -1985,13 +2252,15 @@ static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
 	spec->autocfg.hp_pins[1] = 0x1b; /* hp */
 	spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
 	spec->autocfg.speaker_pins[1] = 0x15; /* bass */
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 /*
  * ALC888 Acer Aspire 4930G model
  */
 
-static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
+static const struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
 /* Front Mic: set to PIN_IN (empty by default) */
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 /* Unselect Front Mic by default in input mixer 3 */
@@ -2014,7 +2283,7 @@ static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
  * ALC888 Acer Aspire 6530G model
  */
 
-static struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
+static const struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
 /* Route to built-in subwoofer as well as speakers */
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -2044,7 +2313,7 @@ static struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
  *ALC888 Acer Aspire 7730G model
  */
 
-static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
+static const struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
 /* Bias voltage on for external mic port */
 	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
 /* Front Mic: set to PIN_IN (empty by default) */
@@ -2074,7 +2343,7 @@ static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
  * ALC889 Acer Aspire 8930G model
  */
 
-static struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
+static const struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
 /* Front Mic: set to PIN_IN (empty by default) */
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 /* Unselect Front Mic by default in input mixer 3 */
@@ -2120,7 +2389,7 @@ static struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
 	{ }
 };
 
-static struct hda_input_mux alc888_2_capture_sources[2] = {
+static const struct hda_input_mux alc888_2_capture_sources[2] = {
 	/* Front mic only available on one ADC */
 	{
 		.num_items = 4,
@@ -2141,7 +2410,7 @@ static struct hda_input_mux alc888_2_capture_sources[2] = {
 	}
 };
 
-static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
+static const struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
 	/* Interal mic only available on one ADC */
 	{
 		.num_items = 5,
@@ -2164,7 +2433,7 @@ static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
 	}
 };
 
-static struct hda_input_mux alc889_capture_sources[3] = {
+static const struct hda_input_mux alc889_capture_sources[3] = {
 	/* Digital mic only available on first "ADC" */
 	{
 		.num_items = 5,
@@ -2196,7 +2465,7 @@ static struct hda_input_mux alc889_capture_sources[3] = {
 	}
 };
 
-static struct snd_kcontrol_new alc888_base_mixer[] = {
+static const struct snd_kcontrol_new alc888_base_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2218,7 +2487,7 @@ static struct snd_kcontrol_new alc888_base_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
+static const struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2240,7 +2509,7 @@ static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
+static const struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2267,6 +2536,8 @@ static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[1] = 0x16;
 	spec->autocfg.speaker_pins[2] = 0x17;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
@@ -2277,6 +2548,8 @@ static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[1] = 0x16;
 	spec->autocfg.speaker_pins[2] = 0x17;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec)
@@ -2287,6 +2560,8 @@ static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec)
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[1] = 0x16;
 	spec->autocfg.speaker_pins[2] = 0x17;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
@@ -2297,6 +2572,8 @@ static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[1] = 0x16;
 	spec->autocfg.speaker_pins[2] = 0x1b;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 /*
@@ -2307,12 +2584,12 @@ static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
  *                 F-Mic = 0x1b, HP = 0x19
  */
 
-static hda_nid_t alc880_dac_nids[4] = {
+static const hda_nid_t alc880_dac_nids[4] = {
 	/* front, rear, clfe, rear_surr */
 	0x02, 0x05, 0x04, 0x03
 };
 
-static hda_nid_t alc880_adc_nids[3] = {
+static const hda_nid_t alc880_adc_nids[3] = {
 	/* ADC0-2 */
 	0x07, 0x08, 0x09,
 };
@@ -2321,7 +2598,7 @@ static hda_nid_t alc880_adc_nids[3] = {
  * but it shows zero connection in the real implementation on some devices.
  * Note: this is a 915GAV bug, fixed on 915GLV
  */
-static hda_nid_t alc880_adc_nids_alt[2] = {
+static const hda_nid_t alc880_adc_nids_alt[2] = {
 	/* ADC1-2 */
 	0x08, 0x09,
 };
@@ -2329,7 +2606,7 @@ static hda_nid_t alc880_adc_nids_alt[2] = {
 #define ALC880_DIGOUT_NID	0x06
 #define ALC880_DIGIN_NID	0x0a
 
-static struct hda_input_mux alc880_capture_source = {
+static const struct hda_input_mux alc880_capture_source = {
 	.num_items = 4,
 	.items = {
 		{ "Mic", 0x0 },
@@ -2341,7 +2618,7 @@ static struct hda_input_mux alc880_capture_source = {
 
 /* channel source setting (2/6 channel selection for 3-stack) */
 /* 2ch mode */
-static struct hda_verb alc880_threestack_ch2_init[] = {
+static const struct hda_verb alc880_threestack_ch2_init[] = {
 	/* set line-in to input, mute it */
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
@@ -2352,7 +2629,7 @@ static struct hda_verb alc880_threestack_ch2_init[] = {
 };
 
 /* 6ch mode */
-static struct hda_verb alc880_threestack_ch6_init[] = {
+static const struct hda_verb alc880_threestack_ch6_init[] = {
 	/* set line-in to output, unmute it */
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
@@ -2362,12 +2639,12 @@ static struct hda_verb alc880_threestack_ch6_init[] = {
 	{ } /* end */
 };
 
-static struct hda_channel_mode alc880_threestack_modes[2] = {
+static const struct hda_channel_mode alc880_threestack_modes[2] = {
 	{ 2, alc880_threestack_ch2_init },
 	{ 6, alc880_threestack_ch6_init },
 };
 
-static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
+static const struct snd_kcontrol_new alc880_three_stack_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
@@ -2512,14 +2789,14 @@ static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
 	}
 
 #define DEFINE_CAPMIX(num) \
-static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
+static const struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
 	_DEFINE_CAPMIX(num),				      \
 	_DEFINE_CAPSRC(num),				      \
 	{ } /* end */					      \
 }
 
 #define DEFINE_CAPMIX_NOSRC(num) \
-static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
+static const struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
 	_DEFINE_CAPMIX(num),					    \
 	{ } /* end */						    \
 }
@@ -2542,7 +2819,7 @@ DEFINE_CAPMIX_NOSRC(3);
  */
 
 /* additional mixers to alc880_three_stack_mixer */
-static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
+static const struct snd_kcontrol_new alc880_five_stack_mixer[] = {
 	HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
 	{ } /* end */
@@ -2550,7 +2827,7 @@ static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
 
 /* channel source setting (6/8 channel selection for 5-stack) */
 /* 6ch mode */
-static struct hda_verb alc880_fivestack_ch6_init[] = {
+static const struct hda_verb alc880_fivestack_ch6_init[] = {
 	/* set line-in to input, mute it */
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
@@ -2558,14 +2835,14 @@ static struct hda_verb alc880_fivestack_ch6_init[] = {
 };
 
 /* 8ch mode */
-static struct hda_verb alc880_fivestack_ch8_init[] = {
+static const struct hda_verb alc880_fivestack_ch8_init[] = {
 	/* set line-in to output, unmute it */
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ } /* end */
 };
 
-static struct hda_channel_mode alc880_fivestack_modes[2] = {
+static const struct hda_channel_mode alc880_fivestack_modes[2] = {
 	{ 6, alc880_fivestack_ch6_init },
 	{ 8, alc880_fivestack_ch8_init },
 };
@@ -2580,12 +2857,12 @@ static struct hda_channel_mode alc880_fivestack_modes[2] = {
  *   Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
  */
 
-static hda_nid_t alc880_6st_dac_nids[4] = {
+static const hda_nid_t alc880_6st_dac_nids[4] = {
 	/* front, rear, clfe, rear_surr */
 	0x02, 0x03, 0x04, 0x05
 };
 
-static struct hda_input_mux alc880_6stack_capture_source = {
+static const struct hda_input_mux alc880_6stack_capture_source = {
 	.num_items = 4,
 	.items = {
 		{ "Mic", 0x0 },
@@ -2596,11 +2873,11 @@ static struct hda_input_mux alc880_6stack_capture_source = {
 };
 
 /* fixed 8-channels */
-static struct hda_channel_mode alc880_sixstack_modes[1] = {
+static const struct hda_channel_mode alc880_sixstack_modes[1] = {
 	{ 8, NULL },
 };
 
-static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
+static const struct snd_kcontrol_new alc880_six_stack_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2655,18 +2932,18 @@ static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
  * haven't setup any initialization verbs for these yet...
  */
 
-static hda_nid_t alc880_w810_dac_nids[3] = {
+static const hda_nid_t alc880_w810_dac_nids[3] = {
 	/* front, rear/surround, clfe */
 	0x02, 0x03, 0x04
 };
 
 /* fixed 6 channels */
-static struct hda_channel_mode alc880_w810_modes[1] = {
+static const struct hda_channel_mode alc880_w810_modes[1] = {
 	{ 6, NULL }
 };
 
 /* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
-static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
+static const struct snd_kcontrol_new alc880_w810_base_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2688,17 +2965,17 @@ static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
  *                 Line = 0x1a
  */
 
-static hda_nid_t alc880_z71v_dac_nids[1] = {
+static const hda_nid_t alc880_z71v_dac_nids[1] = {
 	0x02
 };
 #define ALC880_Z71V_HP_DAC	0x03
 
 /* fixed 2 channels */
-static struct hda_channel_mode alc880_2_jack_modes[1] = {
+static const struct hda_channel_mode alc880_2_jack_modes[1] = {
 	{ 2, NULL }
 };
 
-static struct snd_kcontrol_new alc880_z71v_mixer[] = {
+static const struct snd_kcontrol_new alc880_z71v_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2718,12 +2995,12 @@ static struct snd_kcontrol_new alc880_z71v_mixer[] = {
  * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
  */
 
-static hda_nid_t alc880_f1734_dac_nids[1] = {
+static const hda_nid_t alc880_f1734_dac_nids[1] = {
 	0x03
 };
 #define ALC880_F1734_HP_DAC	0x02
 
-static struct snd_kcontrol_new alc880_f1734_mixer[] = {
+static const struct snd_kcontrol_new alc880_f1734_mixer[] = {
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2735,7 +3012,7 @@ static struct snd_kcontrol_new alc880_f1734_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_input_mux alc880_f1734_capture_source = {
+static const struct hda_input_mux alc880_f1734_capture_source = {
 	.num_items = 2,
 	.items = {
 		{ "Mic", 0x1 },
@@ -2755,7 +3032,7 @@ static struct hda_input_mux alc880_f1734_capture_source = {
 #define alc880_asus_dac_nids	alc880_w810_dac_nids	/* identical with w810 */
 #define alc880_asus_modes	alc880_threestack_modes	/* 2/6 channel mode */
 
-static struct snd_kcontrol_new alc880_asus_mixer[] = {
+static const struct snd_kcontrol_new alc880_asus_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2789,14 +3066,14 @@ static struct snd_kcontrol_new alc880_asus_mixer[] = {
  */
 
 /* additional mixers to alc880_asus_mixer */
-static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
+static const struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
 	HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
 	HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
 	{ } /* end */
 };
 
 /* TCL S700 */
-static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
+static const struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -2810,7 +3087,7 @@ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
 };
 
 /* Uniwill */
-static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
+static const struct snd_kcontrol_new alc880_uniwill_mixer[] = {
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2837,7 +3114,7 @@ static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
+static const struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2851,7 +3128,7 @@ static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
+static const struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2878,7 +3155,6 @@ static const char * const alc_slave_vols[] = {
 	"Speaker Playback Volume",
 	"Mono Playback Volume",
 	"Line-Out Playback Volume",
-	"PCM Playback Volume",
 	NULL,
 };
 
@@ -2893,7 +3169,6 @@ static const char * const alc_slave_sws[] = {
 	"Mono Playback Switch",
 	"IEC958 Playback Switch",
 	"Line-Out Playback Switch",
-	"PCM Playback Switch",
 	NULL,
 };
 
@@ -2914,7 +3189,7 @@ static void alc_free_kctls(struct hda_codec *codec);
 
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 /* additional beep mixers; the actual parameters are overwritten at build */
-static struct snd_kcontrol_new alc_beep_mixer[] = {
+static const struct snd_kcontrol_new alc_beep_mixer[] = {
 	HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
 	HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
 	{ } /* end */
@@ -2925,7 +3200,7 @@ static int alc_build_controls(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 	struct snd_kcontrol *kctl = NULL;
-	struct snd_kcontrol_new *knew;
+	const struct snd_kcontrol_new *knew;
 	int i, j, err;
 	unsigned int u;
 	hda_nid_t nid;
@@ -2962,7 +3237,7 @@ static int alc_build_controls(struct hda_codec *codec)
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 	/* create beep controls if needed */
 	if (spec->beep_amp) {
-		struct snd_kcontrol_new *knew;
+		const struct snd_kcontrol_new *knew;
 		for (knew = alc_beep_mixer; knew->name; knew++) {
 			struct snd_kcontrol *kctl;
 			kctl = snd_ctl_new1(knew, codec);
@@ -3001,7 +3276,7 @@ static int alc_build_controls(struct hda_codec *codec)
 		if (!kctl)
 			kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
 		for (i = 0; kctl && i < kctl->count; i++) {
-			hda_nid_t *nids = spec->capsrc_nids;
+			const hda_nid_t *nids = spec->capsrc_nids;
 			if (!nids)
 				nids = spec->adc_nids;
 			err = snd_hda_add_nid(codec, kctl, i, nids[i]);
@@ -3079,7 +3354,7 @@ static int alc_build_controls(struct hda_codec *codec)
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
-static struct hda_verb alc880_volume_init_verbs[] = {
+static const struct hda_verb alc880_volume_init_verbs[] = {
 	/*
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 */
@@ -3130,7 +3405,7 @@ static struct hda_verb alc880_volume_init_verbs[] = {
  * 3-stack pin configuration:
  * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
  */
-static struct hda_verb alc880_pin_3stack_init_verbs[] = {
+static const struct hda_verb alc880_pin_3stack_init_verbs[] = {
 	/*
 	 * preset connection lists of input pins
 	 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
@@ -3168,7 +3443,7 @@ static struct hda_verb alc880_pin_3stack_init_verbs[] = {
  * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
  * line-in/side = 0x1a, f-mic = 0x1b
  */
-static struct hda_verb alc880_pin_5stack_init_verbs[] = {
+static const struct hda_verb alc880_pin_5stack_init_verbs[] = {
 	/*
 	 * preset connection lists of input pins
 	 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
@@ -3212,7 +3487,7 @@ static struct hda_verb alc880_pin_5stack_init_verbs[] = {
  * W810 pin configuration:
  * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
  */
-static struct hda_verb alc880_pin_w810_init_verbs[] = {
+static const struct hda_verb alc880_pin_w810_init_verbs[] = {
 	/* hphone/speaker input selector: front DAC */
 	{0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
 
@@ -3233,7 +3508,7 @@ static struct hda_verb alc880_pin_w810_init_verbs[] = {
  * Z71V pin configuration:
  * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
  */
-static struct hda_verb alc880_pin_z71v_init_verbs[] = {
+static const struct hda_verb alc880_pin_z71v_init_verbs[] = {
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -3252,7 +3527,7 @@ static struct hda_verb alc880_pin_z71v_init_verbs[] = {
  * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
  * f-mic = 0x19, line = 0x1a, HP = 0x1b
  */
-static struct hda_verb alc880_pin_6stack_init_verbs[] = {
+static const struct hda_verb alc880_pin_6stack_init_verbs[] = {
 	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
 
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
@@ -3282,7 +3557,7 @@ static struct hda_verb alc880_pin_6stack_init_verbs[] = {
  * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
  * line = 0x1a
  */
-static struct hda_verb alc880_uniwill_init_verbs[] = {
+static const struct hda_verb alc880_uniwill_init_verbs[] = {
 	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
 
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -3320,7 +3595,7 @@ static struct hda_verb alc880_uniwill_init_verbs[] = {
 * Uniwill P53
 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
  */
-static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
+static const struct hda_verb alc880_uniwill_p53_init_verbs[] = {
 	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
 
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -3349,7 +3624,7 @@ static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb alc880_beep_init_verbs[] = {
+static const struct hda_verb alc880_beep_init_verbs[] = {
 	{ 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
 	{ }
 };
@@ -3372,11 +3647,13 @@ static void alc880_uniwill_setup(struct hda_codec *codec)
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x16;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 static void alc880_uniwill_init_hook(struct hda_codec *codec)
 {
-	alc_automute_amp(codec);
+	alc_hp_automute(codec);
 	alc88x_simple_mic_automute(codec);
 }
 
@@ -3391,7 +3668,7 @@ static void alc880_uniwill_unsol_event(struct hda_codec *codec,
 		alc88x_simple_mic_automute(codec);
 		break;
 	default:
-		alc_automute_amp_unsol_event(codec, res);
+		alc_sku_unsol_event(codec, res);
 		break;
 	}
 }
@@ -3402,6 +3679,8 @@ static void alc880_uniwill_p53_setup(struct hda_codec *codec)
 
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x15;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
@@ -3426,14 +3705,14 @@ static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
 	if ((res >> 28) == ALC880_DCVOL_EVENT)
 		alc880_uniwill_p53_dcvol_automute(codec);
 	else
-		alc_automute_amp_unsol_event(codec, res);
+		alc_sku_unsol_event(codec, res);
 }
 
 /*
  * F1734 pin configuration:
  * HP = 0x14, speaker-out = 0x15, mic = 0x18
  */
-static struct hda_verb alc880_pin_f1734_init_verbs[] = {
+static const struct hda_verb alc880_pin_f1734_init_verbs[] = {
 	{0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
 	{0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -3465,7 +3744,7 @@ static struct hda_verb alc880_pin_f1734_init_verbs[] = {
  * ASUS pin configuration:
  * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
  */
-static struct hda_verb alc880_pin_asus_init_verbs[] = {
+static const struct hda_verb alc880_pin_asus_init_verbs[] = {
 	{0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
 	{0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
@@ -3499,7 +3778,7 @@ static struct hda_verb alc880_pin_asus_init_verbs[] = {
 #define alc880_gpio3_init_verbs	alc_gpio3_init_verbs
 
 /* Clevo m520g init */
-static struct hda_verb alc880_pin_clevo_init_verbs[] = {
+static const struct hda_verb alc880_pin_clevo_init_verbs[] = {
 	/* headphone output */
 	{0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
 	/* line-out */
@@ -3527,7 +3806,7 @@ static struct hda_verb alc880_pin_clevo_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
+static const struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
 	/* change to EAPD mode */
 	{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
 	{0x20, AC_VERB_SET_PROC_COEF,  0x3060},
@@ -3565,12 +3844,12 @@ static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
  */
 
 /* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
-static hda_nid_t alc880_lg_dac_nids[3] = {
+static const hda_nid_t alc880_lg_dac_nids[3] = {
 	0x05, 0x02, 0x03
 };
 
 /* seems analog CD is not working */
-static struct hda_input_mux alc880_lg_capture_source = {
+static const struct hda_input_mux alc880_lg_capture_source = {
 	.num_items = 3,
 	.items = {
 		{ "Mic", 0x1 },
@@ -3580,34 +3859,34 @@ static struct hda_input_mux alc880_lg_capture_source = {
 };
 
 /* 2,4,6 channel modes */
-static struct hda_verb alc880_lg_ch2_init[] = {
+static const struct hda_verb alc880_lg_ch2_init[] = {
 	/* set line-in and mic-in to input */
 	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ }
 };
 
-static struct hda_verb alc880_lg_ch4_init[] = {
+static const struct hda_verb alc880_lg_ch4_init[] = {
 	/* set line-in to out and mic-in to input */
 	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
 	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ }
 };
 
-static struct hda_verb alc880_lg_ch6_init[] = {
+static const struct hda_verb alc880_lg_ch6_init[] = {
 	/* set line-in and mic-in to output */
 	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
 	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
 	{ }
 };
 
-static struct hda_channel_mode alc880_lg_ch_modes[3] = {
+static const struct hda_channel_mode alc880_lg_ch_modes[3] = {
 	{ 2, alc880_lg_ch2_init },
 	{ 4, alc880_lg_ch4_init },
 	{ 6, alc880_lg_ch6_init },
 };
 
-static struct snd_kcontrol_new alc880_lg_mixer[] = {
+static const struct snd_kcontrol_new alc880_lg_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
@@ -3632,7 +3911,7 @@ static struct snd_kcontrol_new alc880_lg_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc880_lg_init_verbs[] = {
+static const struct hda_verb alc880_lg_init_verbs[] = {
 	/* set capture source to mic-in */
 	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -3670,6 +3949,8 @@ static void alc880_lg_setup(struct hda_codec *codec)
 
 	spec->autocfg.hp_pins[0] = 0x1b;
 	spec->autocfg.speaker_pins[0] = 0x17;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 /*
@@ -3684,7 +3965,7 @@ static void alc880_lg_setup(struct hda_codec *codec)
  *   SPDIF-Out: 0x1e
  */
 
-static struct hda_input_mux alc880_lg_lw_capture_source = {
+static const struct hda_input_mux alc880_lg_lw_capture_source = {
 	.num_items = 3,
 	.items = {
 		{ "Mic", 0x0 },
@@ -3695,7 +3976,7 @@ static struct hda_input_mux alc880_lg_lw_capture_source = {
 
 #define alc880_lg_lw_modes alc880_threestack_modes
 
-static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
+static const struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
@@ -3720,7 +4001,7 @@ static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc880_lg_lw_init_verbs[] = {
+static const struct hda_verb alc880_lg_lw_init_verbs[] = {
 	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
 	{0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
 	{0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
@@ -3754,9 +4035,11 @@ static void alc880_lg_lw_setup(struct hda_codec *codec)
 
 	spec->autocfg.hp_pins[0] = 0x1b;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
-static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
+static const struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -3766,7 +4049,7 @@ static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_input_mux alc880_medion_rim_capture_source = {
+static const struct hda_input_mux alc880_medion_rim_capture_source = {
 	.num_items = 2,
 	.items = {
 		{ "Mic", 0x0 },
@@ -3774,7 +4057,7 @@ static struct hda_input_mux alc880_medion_rim_capture_source = {
 	},
 };
 
-static struct hda_verb alc880_medion_rim_init_verbs[] = {
+static const struct hda_verb alc880_medion_rim_init_verbs[] = {
 	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
 
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -3801,7 +4084,7 @@ static struct hda_verb alc880_medion_rim_init_verbs[] = {
 static void alc880_medion_rim_automute(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
-	alc_automute_amp(codec);
+	alc_hp_automute(codec);
 	/* toggle EAPD */
 	if (spec->jack_present)
 		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
@@ -3825,10 +4108,12 @@ static void alc880_medion_rim_setup(struct hda_codec *codec)
 
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x1b;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list alc880_loopbacks[] = {
+static const struct hda_amp_list alc880_loopbacks[] = {
 	{ 0x0b, HDA_INPUT, 0 },
 	{ 0x0b, HDA_INPUT, 1 },
 	{ 0x0b, HDA_INPUT, 2 },
@@ -3837,7 +4122,7 @@ static struct hda_amp_list alc880_loopbacks[] = {
 	{ } /* end */
 };
 
-static struct hda_amp_list alc880_lg_loopbacks[] = {
+static const struct hda_amp_list alc880_lg_loopbacks[] = {
 	{ 0x0b, HDA_INPUT, 1 },
 	{ 0x0b, HDA_INPUT, 6 },
 	{ 0x0b, HDA_INPUT, 7 },
@@ -4009,7 +4294,7 @@ static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 	return 0;
 }
 
-static struct hda_pcm_stream dualmic_pcm_analog_capture = {
+static const struct hda_pcm_stream dualmic_pcm_analog_capture = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -4022,7 +4307,7 @@ static struct hda_pcm_stream dualmic_pcm_analog_capture = {
 
 /*
  */
-static struct hda_pcm_stream alc880_pcm_analog_playback = {
+static const struct hda_pcm_stream alc880_pcm_analog_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 8,
@@ -4034,21 +4319,21 @@ static struct hda_pcm_stream alc880_pcm_analog_playback = {
 	},
 };
 
-static struct hda_pcm_stream alc880_pcm_analog_capture = {
+static const struct hda_pcm_stream alc880_pcm_analog_capture = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
 	/* NID is set in alc_build_pcms */
 };
 
-static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
+static const struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
 	/* NID is set in alc_build_pcms */
 };
 
-static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
+static const struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
 	.substreams = 2, /* can be overridden */
 	.channels_min = 2,
 	.channels_max = 2,
@@ -4059,7 +4344,7 @@ static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
 	},
 };
 
-static struct hda_pcm_stream alc880_pcm_digital_playback = {
+static const struct hda_pcm_stream alc880_pcm_digital_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -4072,7 +4357,7 @@ static struct hda_pcm_stream alc880_pcm_digital_playback = {
 	},
 };
 
-static struct hda_pcm_stream alc880_pcm_digital_capture = {
+static const struct hda_pcm_stream alc880_pcm_digital_capture = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -4080,7 +4365,7 @@ static struct hda_pcm_stream alc880_pcm_digital_capture = {
 };
 
 /* Used by alc_build_pcms to flag that a PCM has no playback stream */
-static struct hda_pcm_stream alc_pcm_null_stream = {
+static const struct hda_pcm_stream alc_pcm_null_stream = {
 	.substreams = 0,
 	.channels_min = 0,
 	.channels_max = 0,
@@ -4174,7 +4459,7 @@ static int alc_build_pcms(struct hda_codec *codec)
 				alc_pcm_null_stream;
 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
 		}
-		if (spec->num_adc_nids > 1) {
+		if (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture) {
 			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
 				*spec->stream_analog_alt_capture;
 			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
@@ -4193,6 +4478,10 @@ static int alc_build_pcms(struct hda_codec *codec)
 
 static inline void alc_shutup(struct hda_codec *codec)
 {
+	struct alc_spec *spec = codec->spec;
+
+	if (spec && spec->shutup)
+		spec->shutup(codec);
 	snd_hda_shutup_pins(codec);
 }
 
@@ -4226,28 +4515,7 @@ static void alc_free(struct hda_codec *codec)
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 static void alc_power_eapd(struct hda_codec *codec)
 {
-	/* We currently only handle front, HP */
-	switch (codec->vendor_id) {
-	case 0x10ec0260:
-		set_eapd(codec, 0x0f, 0);
-		set_eapd(codec, 0x10, 0);
-		break;
-	case 0x10ec0262:
-	case 0x10ec0267:
-	case 0x10ec0268:
-	case 0x10ec0269:
-	case 0x10ec0270:
-	case 0x10ec0272:
-	case 0x10ec0660:
-	case 0x10ec0662:
-	case 0x10ec0663:
-	case 0x10ec0665:
-	case 0x10ec0862:
-	case 0x10ec0889:
-		set_eapd(codec, 0x14, 0);
-		set_eapd(codec, 0x15, 0);
-		break;
-	}
+	alc_auto_setup_eapd(codec, false);
 }
 
 static int alc_suspend(struct hda_codec *codec, pm_message_t state)
@@ -4263,6 +4531,7 @@ static int alc_suspend(struct hda_codec *codec, pm_message_t state)
 #ifdef SND_HDA_NEEDS_RESUME
 static int alc_resume(struct hda_codec *codec)
 {
+	msleep(150); /* to avoid pop noise */
 	codec->patch_ops.init(codec);
 	snd_hda_codec_resume_amp(codec);
 	snd_hda_codec_resume_cache(codec);
@@ -4273,7 +4542,7 @@ static int alc_resume(struct hda_codec *codec)
 
 /*
  */
-static struct hda_codec_ops alc_patch_ops = {
+static const struct hda_codec_ops alc_patch_ops = {
 	.build_controls = alc_build_controls,
 	.build_pcms = alc_build_pcms,
 	.init = alc_init,
@@ -4308,11 +4577,11 @@ static int alc_codec_rename(struct hda_codec *codec, const char *name)
  * enum controls.
  */
 #ifdef CONFIG_SND_DEBUG
-static hda_nid_t alc880_test_dac_nids[4] = {
+static const hda_nid_t alc880_test_dac_nids[4] = {
 	0x02, 0x03, 0x04, 0x05
 };
 
-static struct hda_input_mux alc880_test_capture_source = {
+static const struct hda_input_mux alc880_test_capture_source = {
 	.num_items = 7,
 	.items = {
 		{ "In-1", 0x0 },
@@ -4325,7 +4594,7 @@ static struct hda_input_mux alc880_test_capture_source = {
 	},
 };
 
-static struct hda_channel_mode alc880_test_modes[4] = {
+static const struct hda_channel_mode alc880_test_modes[4] = {
 	{ 2, NULL },
 	{ 4, NULL },
 	{ 6, NULL },
@@ -4335,7 +4604,7 @@ static struct hda_channel_mode alc880_test_modes[4] = {
 static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = {
+	static const char * const texts[] = {
 		"N/A", "Line Out", "HP Out",
 		"In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
 	};
@@ -4380,7 +4649,7 @@ static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
-	static unsigned int ctls[] = {
+	static const unsigned int ctls[] = {
 		0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
 		AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
 		AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
@@ -4410,7 +4679,7 @@ static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
 static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = {
+	static const char * const texts[] = {
 		"Front", "Surround", "CLFE", "Side"
 	};
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
@@ -4471,7 +4740,7 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
 			.private_value = nid	       \
 			}
 
-static struct snd_kcontrol_new alc880_test_mixer[] = {
+static const struct snd_kcontrol_new alc880_test_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
@@ -4512,7 +4781,7 @@ static struct snd_kcontrol_new alc880_test_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc880_test_init_verbs[] = {
+static const struct hda_verb alc880_test_init_verbs[] = {
 	/* Unmute inputs of 0x0c - 0x0f */
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -4596,7 +4865,7 @@ static const char * const alc880_models[ALC880_MODEL_LAST] = {
 	[ALC880_AUTO]		= "auto",
 };
 
-static struct snd_pci_quirk alc880_cfg_tbl[] = {
+static const struct snd_pci_quirk alc880_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
 	SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
 	SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
@@ -4676,7 +4945,7 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = {
 /*
  * ALC880 codec presets
  */
-static struct alc_config_preset alc880_presets[] = {
+static const struct alc_config_preset alc880_presets[] = {
 	[ALC880_3ST] = {
 		.mixers = { alc880_three_stack_mixer },
 		.init_verbs = { alc880_volume_init_verbs,
@@ -4794,7 +5063,7 @@ static struct alc_config_preset alc880_presets[] = {
 		.input_mux = &alc880_f1734_capture_source,
 		.unsol_event = alc880_uniwill_p53_unsol_event,
 		.setup = alc880_uniwill_p53_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC880_ASUS] = {
 		.mixers = { alc880_asus_mixer },
@@ -4885,7 +5154,7 @@ static struct alc_config_preset alc880_presets[] = {
 		.input_mux = &alc880_capture_source,
 		.unsol_event = alc880_uniwill_p53_unsol_event,
 		.setup = alc880_uniwill_p53_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC880_FUJITSU] = {
 		.mixers = { alc880_fujitsu_mixer },
@@ -4900,7 +5169,7 @@ static struct alc_config_preset alc880_presets[] = {
 		.input_mux = &alc880_capture_source,
 		.unsol_event = alc880_uniwill_p53_unsol_event,
 		.setup = alc880_uniwill_p53_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC880_CLEVO] = {
 		.mixers = { alc880_three_stack_mixer },
@@ -4925,9 +5194,9 @@ static struct alc_config_preset alc880_presets[] = {
 		.channel_mode = alc880_lg_ch_modes,
 		.need_dac_fix = 1,
 		.input_mux = &alc880_lg_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc880_lg_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 		.loopbacks = alc880_lg_loopbacks,
 #endif
@@ -4942,9 +5211,9 @@ static struct alc_config_preset alc880_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
 		.channel_mode = alc880_lg_lw_modes,
 		.input_mux = &alc880_lg_lw_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc880_lg_lw_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC880_MEDION_RIM] = {
 		.mixers = { alc880_medion_rim_mixer },
@@ -4984,20 +5253,25 @@ enum {
 	ALC_CTL_WIDGET_MUTE,
 	ALC_CTL_BIND_MUTE,
 };
-static struct snd_kcontrol_new alc880_control_templates[] = {
+static const struct snd_kcontrol_new alc880_control_templates[] = {
 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
 	HDA_CODEC_MUTE(NULL, 0, 0, 0),
 	HDA_BIND_MUTE(NULL, 0, 0, 0),
 };
 
+static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec)
+{
+	snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
+	return snd_array_new(&spec->kctls);
+}
+
 /* add dynamic controls */
 static int add_control(struct alc_spec *spec, int type, const char *name,
 		       int cidx, unsigned long val)
 {
 	struct snd_kcontrol_new *knew;
 
-	snd_array_init(&spec->kctls, sizeof(*knew), 32);
-	knew = snd_array_new(&spec->kctls);
+	knew = alc_kcontrol_new(spec);
 	if (!knew)
 		return -ENOMEM;
 	*knew = alc880_control_templates[type];
@@ -5055,7 +5329,7 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
 		nid = cfg->line_out_pins[i];
 		if (alc880_is_fixed_pin(nid)) {
 			int idx = alc880_fixed_pin_idx(nid);
-			spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
+			spec->private_dac_nids[i] = alc880_idx_to_dac(idx);
 			assigned[idx] = 1;
 		}
 	}
@@ -5067,7 +5341,7 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
 		/* search for an empty channel */
 		for (j = 0; j < cfg->line_outs; j++) {
 			if (!assigned[j]) {
-				spec->multiout.dac_nids[i] =
+				spec->private_dac_nids[i] =
 					alc880_idx_to_dac(j);
 				assigned[j] = 1;
 				break;
@@ -5078,10 +5352,13 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
 	return 0;
 }
 
-static const char *alc_get_line_out_pfx(const struct auto_pin_cfg *cfg,
+static const char *alc_get_line_out_pfx(struct alc_spec *spec,
 					bool can_be_master)
 {
-	if (!cfg->hp_outs && !cfg->speaker_outs && can_be_master)
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+
+	if (cfg->line_outs == 1 && !spec->multi_ios &&
+	    !cfg->hp_outs && !cfg->speaker_outs && can_be_master)
 		return "Master";
 
 	switch (cfg->line_out_type) {
@@ -5092,7 +5369,7 @@ static const char *alc_get_line_out_pfx(const struct auto_pin_cfg *cfg,
 	case AUTO_PIN_HP_OUT:
 		return "Headphone";
 	default:
-		if (cfg->line_outs == 1)
+		if (cfg->line_outs == 1 && !spec->multi_ios)
 			return "PCM";
 		break;
 	}
@@ -5106,11 +5383,15 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
 	static const char * const chname[4] = {
 		"Front", "Surround", NULL /*CLFE*/, "Side"
 	};
-	const char *pfx = alc_get_line_out_pfx(cfg, false);
+	const char *pfx = alc_get_line_out_pfx(spec, false);
 	hda_nid_t nid;
-	int i, err;
+	int i, err, noutputs;
 
-	for (i = 0; i < cfg->line_outs; i++) {
+	noutputs = cfg->line_outs;
+	if (spec->multi_ios > 0)
+		noutputs += spec->multi_ios;
+
+	for (i = 0; i < noutputs; i++) {
 		if (!spec->multiout.dac_nids[i])
 			continue;
 		nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
@@ -5376,6 +5657,8 @@ static void alc880_auto_init_input_src(struct hda_codec *codec)
 	}
 }
 
+static int alc_auto_add_multi_channel_mode(struct hda_codec *codec);
+
 /* parse the BIOS configuration and set up the alc_spec */
 /* return 1 if successful, 0 if the proper config is not found,
  * or a negative error code
@@ -5384,7 +5667,7 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 	int err;
-	static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
+	static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
 
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 					   alc880_ignore);
@@ -5396,6 +5679,9 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
 	err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
 	if (err < 0)
 		return err;
+	err = alc_auto_add_multi_channel_mode(codec);
+	if (err < 0)
+		return err;
 	err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
 	if (err < 0)
 		return err;
@@ -5467,6 +5753,12 @@ static void fixup_automic_adc(struct hda_codec *codec)
 			spec->capsrc_nids += i;
 		spec->adc_nids += i;
 		spec->num_adc_nids = 1;
+		/* optional dock-mic */
+		eidx = get_connection_index(codec, cap, spec->dock_mic.pin);
+		if (eidx < 0)
+			spec->dock_mic.pin = 0;
+		else
+			spec->dock_mic.mux_idx = eidx;
 		return;
 	}
 	snd_printd(KERN_INFO "hda_codec: %s: "
@@ -5494,6 +5786,8 @@ static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
 	struct alc_spec *spec = codec->spec;
 	int i;
 
+	if (!pin)
+		return 0;
 	for (i = 0; i < spec->num_adc_nids; i++) {
 		hda_nid_t cap = spec->capsrc_nids ?
 			spec->capsrc_nids[i] : spec->adc_nids[i];
@@ -5534,6 +5828,7 @@ static void fixup_dual_adc_switch(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 	init_capsrc_for_pin(codec, spec->ext_mic.pin);
+	init_capsrc_for_pin(codec, spec->dock_mic.pin);
 	init_capsrc_for_pin(codec, spec->int_mic.pin);
 }
 
@@ -5550,7 +5845,7 @@ static void alc_init_special_input_src(struct hda_codec *codec)
 static void set_capture_mixer(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
-	static struct snd_kcontrol_new *caps[2][3] = {
+	static const struct snd_kcontrol_new *caps[2][3] = {
 		{ alc_capture_mixer_nosrc1,
 		  alc_capture_mixer_nosrc2,
 		  alc_capture_mixer_nosrc3 },
@@ -5576,7 +5871,7 @@ static void set_capture_mixer(struct hda_codec *codec)
 }
 
 /* fill adc_nids (and capsrc_nids) containing all active input pins */
-static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
+static void fillup_priv_adc_nids(struct hda_codec *codec, const hda_nid_t *nids,
 				 int num_nids)
 {
 	struct alc_spec *spec = codec->spec;
@@ -5642,10 +5937,11 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
 #define set_beep_amp(spec, nid, idx, dir) \
 	((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
 
-static struct snd_pci_quirk beep_white_list[] = {
+static const struct snd_pci_quirk beep_white_list[] = {
 	SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
 	SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
 	SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
+	SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
 	SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
 	{}
 };
@@ -5753,17 +6049,17 @@ static int patch_alc880(struct hda_codec *codec)
  * ALC260 support
  */
 
-static hda_nid_t alc260_dac_nids[1] = {
+static const hda_nid_t alc260_dac_nids[1] = {
 	/* front */
 	0x02,
 };
 
-static hda_nid_t alc260_adc_nids[1] = {
+static const hda_nid_t alc260_adc_nids[1] = {
 	/* ADC0 */
 	0x04,
 };
 
-static hda_nid_t alc260_adc_nids_alt[1] = {
+static const hda_nid_t alc260_adc_nids_alt[1] = {
 	/* ADC1 */
 	0x05,
 };
@@ -5771,7 +6067,7 @@ static hda_nid_t alc260_adc_nids_alt[1] = {
 /* NIDs used when simultaneous access to both ADCs makes sense.  Note that
  * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
  */
-static hda_nid_t alc260_dual_adc_nids[2] = {
+static const hda_nid_t alc260_dual_adc_nids[2] = {
 	/* ADC0, ADC1 */
 	0x04, 0x05
 };
@@ -5779,7 +6075,7 @@ static hda_nid_t alc260_dual_adc_nids[2] = {
 #define ALC260_DIGOUT_NID	0x03
 #define ALC260_DIGIN_NID	0x06
 
-static struct hda_input_mux alc260_capture_source = {
+static const struct hda_input_mux alc260_capture_source = {
 	.num_items = 4,
 	.items = {
 		{ "Mic", 0x0 },
@@ -5795,7 +6091,7 @@ static struct hda_input_mux alc260_capture_source = {
  * recording the mixer output on the second ADC (ADC0 doesn't have a
  * connection to the mixer output).
  */
-static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
+static const struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
 	{
 		.num_items = 3,
 		.items = {
@@ -5819,7 +6115,7 @@ static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
 /* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
  * the Fujitsu S702x, but jacks are marked differently.
  */
-static struct hda_input_mux alc260_acer_capture_sources[2] = {
+static const struct hda_input_mux alc260_acer_capture_sources[2] = {
 	{
 		.num_items = 4,
 		.items = {
@@ -5842,7 +6138,7 @@ static struct hda_input_mux alc260_acer_capture_sources[2] = {
 };
 
 /* Maxdata Favorit 100XS */
-static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
+static const struct hda_input_mux alc260_favorit100_capture_sources[2] = {
 	{
 		.num_items = 2,
 		.items = {
@@ -5866,7 +6162,7 @@ static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
  * element which allows changing the channel mode, so the verb list is
  * never used.
  */
-static struct hda_channel_mode alc260_modes[1] = {
+static const struct hda_channel_mode alc260_modes[1] = {
 	{ 2, NULL },
 };
 
@@ -5880,7 +6176,7 @@ static struct hda_channel_mode alc260_modes[1] = {
  * acer: acer + capture
  */
 
-static struct snd_kcontrol_new alc260_base_output_mixer[] = {
+static const struct snd_kcontrol_new alc260_base_output_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
@@ -5890,7 +6186,7 @@ static struct snd_kcontrol_new alc260_base_output_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc260_input_mixer[] = {
+static const struct snd_kcontrol_new alc260_input_mixer[] = {
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
 	HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
@@ -5903,21 +6199,14 @@ static struct snd_kcontrol_new alc260_input_mixer[] = {
 };
 
 /* update HP, line and mono out pins according to the master switch */
-static void alc260_hp_master_update(struct hda_codec *codec,
-				    hda_nid_t hp, hda_nid_t line,
-				    hda_nid_t mono)
+static void alc260_hp_master_update(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
-	unsigned int val = spec->master_sw ? PIN_HP : 0;
-	/* change HP and line-out pins */
-	snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    val);
-	snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    val);
-	/* mono (speaker) depending on the HP jack sense */
-	val = (val && !spec->jack_present) ? PIN_OUT : 0;
-	snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    val);
+
+	/* change HP pins */
+	do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
+		    spec->autocfg.hp_pins, spec->master_mute, true);
+	update_speakers(codec);
 }
 
 static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
@@ -5925,7 +6214,7 @@ static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct alc_spec *spec = codec->spec;
-	*ucontrol->value.integer.value = spec->master_sw;
+	*ucontrol->value.integer.value = !spec->master_mute;
 	return 0;
 }
 
@@ -5934,20 +6223,16 @@ static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct alc_spec *spec = codec->spec;
-	int val = !!*ucontrol->value.integer.value;
-	hda_nid_t hp, line, mono;
+	int val = !*ucontrol->value.integer.value;
 
-	if (val == spec->master_sw)
+	if (val == spec->master_mute)
 		return 0;
-	spec->master_sw = val;
-	hp = (kcontrol->private_value >> 16) & 0xff;
-	line = (kcontrol->private_value >> 8) & 0xff;
-	mono = kcontrol->private_value & 0xff;
-	alc260_hp_master_update(codec, hp, line, mono);
+	spec->master_mute = val;
+	alc260_hp_master_update(codec);
 	return 1;
 }
 
-static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
+static const struct snd_kcontrol_new alc260_hp_output_mixer[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
@@ -5955,7 +6240,6 @@ static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
 		.info = snd_ctl_boolean_mono_info,
 		.get = alc260_hp_master_sw_get,
 		.put = alc260_hp_master_sw_put,
-		.private_value = (0x0f << 16) | (0x10 << 8) | 0x11
 	},
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
@@ -5967,26 +6251,23 @@ static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc260_hp_unsol_verbs[] = {
+static const struct hda_verb alc260_hp_unsol_verbs[] = {
 	{0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{},
 };
 
-static void alc260_hp_automute(struct hda_codec *codec)
+static void alc260_hp_setup(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 
-	spec->jack_present = snd_hda_jack_detect(codec, 0x10);
-	alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
-}
-
-static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc260_hp_automute(codec);
+	spec->autocfg.hp_pins[0] = 0x0f;
+	spec->autocfg.speaker_pins[0] = 0x10;
+	spec->autocfg.speaker_pins[1] = 0x11;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
 }
 
-static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
+static const struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
@@ -5994,7 +6275,6 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
 		.info = snd_ctl_boolean_mono_info,
 		.get = alc260_hp_master_sw_get,
 		.put = alc260_hp_master_sw_put,
-		.private_value = (0x15 << 16) | (0x10 << 8) | 0x11
 	},
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
@@ -6007,7 +6287,18 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
+static void alc260_hp_3013_setup(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x10;
+	spec->autocfg.speaker_pins[1] = 0x11;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
+}
+
+static const struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
 	.ops = &snd_hda_bind_vol,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
@@ -6017,7 +6308,7 @@ static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
 	},
 };
 
-static struct hda_bind_ctls alc260_dc7600_bind_switch = {
+static const struct hda_bind_ctls alc260_dc7600_bind_switch = {
 	.ops = &snd_hda_bind_sw,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
@@ -6026,7 +6317,7 @@ static struct hda_bind_ctls alc260_dc7600_bind_switch = {
 	},
 };
 
-static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
+static const struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
 	HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
 	HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
@@ -6034,49 +6325,27 @@ static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
+static const struct hda_verb alc260_hp_3013_unsol_verbs[] = {
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{},
 };
 
-static void alc260_hp_3013_automute(struct hda_codec *codec)
+static void alc260_hp_3012_setup(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 
-	spec->jack_present = snd_hda_jack_detect(codec, 0x15);
-	alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
-}
-
-static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
-				       unsigned int res)
-{
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc260_hp_3013_automute(codec);
-}
-
-static void alc260_hp_3012_automute(struct hda_codec *codec)
-{
-	unsigned int bits = snd_hda_jack_detect(codec, 0x10) ? 0 : PIN_OUT;
-
-	snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    bits);
-	snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    bits);
-	snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    bits);
-}
-
-static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
-				       unsigned int res)
-{
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc260_hp_3012_automute(codec);
+	spec->autocfg.hp_pins[0] = 0x10;
+	spec->autocfg.speaker_pins[0] = 0x0f;
+	spec->autocfg.speaker_pins[1] = 0x11;
+	spec->autocfg.speaker_pins[2] = 0x15;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
 }
 
 /* Fujitsu S702x series laptops.  ALC260 pin usage: Mic/Line jack = 0x12,
  * HP jack = 0x14, CD audio =  0x16, internal speaker = 0x10.
  */
-static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
+static const struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
 	ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
@@ -6113,7 +6382,7 @@ static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
  * controls for such models.  On models without a "mono speaker" the control
  * won't do anything.
  */
-static struct snd_kcontrol_new alc260_acer_mixer[] = {
+static const struct snd_kcontrol_new alc260_acer_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
 	ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
@@ -6134,7 +6403,7 @@ static struct snd_kcontrol_new alc260_acer_mixer[] = {
 
 /* Maxdata Favorit 100XS: one output and one input (0x12) jack
  */
-static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
+static const struct snd_kcontrol_new alc260_favorit100_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
 	ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
@@ -6147,7 +6416,7 @@ static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
 /* Packard bell V7900  ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
  * Line In jack = 0x14, CD audio =  0x16, pc beep = 0x17.
  */
-static struct snd_kcontrol_new alc260_will_mixer[] = {
+static const struct snd_kcontrol_new alc260_will_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
@@ -6164,7 +6433,7 @@ static struct snd_kcontrol_new alc260_will_mixer[] = {
 /* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
  * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
  */
-static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
+static const struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
@@ -6181,7 +6450,7 @@ static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
 /*
  * initialization verbs
  */
-static struct hda_verb alc260_init_verbs[] = {
+static const struct hda_verb alc260_init_verbs[] = {
 	/* Line In pin widget for input */
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	/* CD pin widget for input */
@@ -6245,7 +6514,7 @@ static struct hda_verb alc260_init_verbs[] = {
 };
 
 #if 0 /* should be identical with alc260_init_verbs? */
-static struct hda_verb alc260_hp_init_verbs[] = {
+static const struct hda_verb alc260_hp_init_verbs[] = {
 	/* Headphone and output */
 	{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
 	/* mono output */
@@ -6295,7 +6564,7 @@ static struct hda_verb alc260_hp_init_verbs[] = {
 };
 #endif
 
-static struct hda_verb alc260_hp_3013_init_verbs[] = {
+static const struct hda_verb alc260_hp_3013_init_verbs[] = {
 	/* Line out and output */
 	{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
 	/* mono output */
@@ -6348,7 +6617,7 @@ static struct hda_verb alc260_hp_3013_init_verbs[] = {
  * laptops.  ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
  * audio = 0x16, internal speaker = 0x10.
  */
-static struct hda_verb alc260_fujitsu_init_verbs[] = {
+static const struct hda_verb alc260_fujitsu_init_verbs[] = {
 	/* Disable all GPIOs */
 	{0x01, AC_VERB_SET_GPIO_MASK, 0},
 	/* Internal speaker is connected to headphone pin */
@@ -6430,7 +6699,7 @@ static struct hda_verb alc260_fujitsu_init_verbs[] = {
 /* Initialisation sequence for ALC260 as configured in Acer TravelMate and
  * similar laptops (adapted from Fujitsu init verbs).
  */
-static struct hda_verb alc260_acer_init_verbs[] = {
+static const struct hda_verb alc260_acer_init_verbs[] = {
 	/* On TravelMate laptops, GPIO 0 enables the internal speaker and
 	 * the headphone jack.  Turn this on and rely on the standard mute
 	 * methods whenever the user wants to turn these outputs off.
@@ -6518,7 +6787,7 @@ static struct hda_verb alc260_acer_init_verbs[] = {
 /* Initialisation sequence for Maxdata Favorit 100XS
  * (adapted from Acer init verbs).
  */
-static struct hda_verb alc260_favorit100_init_verbs[] = {
+static const struct hda_verb alc260_favorit100_init_verbs[] = {
 	/* GPIO 0 enables the output jack.
 	 * Turn this on and rely on the standard mute
 	 * methods whenever the user wants to turn these outputs off.
@@ -6598,7 +6867,7 @@ static struct hda_verb alc260_favorit100_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb alc260_will_verbs[] = {
+static const struct hda_verb alc260_will_verbs[] = {
 	{0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -6608,7 +6877,7 @@ static struct hda_verb alc260_will_verbs[] = {
 	{}
 };
 
-static struct hda_verb alc260_replacer_672v_verbs[] = {
+static const struct hda_verb alc260_replacer_672v_verbs[] = {
 	{0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
 	{0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
 	{0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
@@ -6650,7 +6919,7 @@ static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
                 alc260_replacer_672v_automute(codec);
 }
 
-static struct hda_verb alc260_hp_dc7600_verbs[] = {
+static const struct hda_verb alc260_hp_dc7600_verbs[] = {
 	{0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
@@ -6668,17 +6937,17 @@ static struct hda_verb alc260_hp_dc7600_verbs[] = {
  * configuration.
  */
 #ifdef CONFIG_SND_DEBUG
-static hda_nid_t alc260_test_dac_nids[1] = {
+static const hda_nid_t alc260_test_dac_nids[1] = {
 	0x02,
 };
-static hda_nid_t alc260_test_adc_nids[2] = {
+static const hda_nid_t alc260_test_adc_nids[2] = {
 	0x04, 0x05,
 };
 /* For testing the ALC260, each input MUX needs its own definition since
  * the signal assignments are different.  This assumes that the first ADC
  * is NID 0x04.
  */
-static struct hda_input_mux alc260_test_capture_sources[2] = {
+static const struct hda_input_mux alc260_test_capture_sources[2] = {
 	{
 		.num_items = 7,
 		.items = {
@@ -6705,7 +6974,7 @@ static struct hda_input_mux alc260_test_capture_sources[2] = {
 		},
         },
 };
-static struct snd_kcontrol_new alc260_test_mixer[] = {
+static const struct snd_kcontrol_new alc260_test_mixer[] = {
 	/* Output driver widgets */
 	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
@@ -6769,7 +7038,7 @@ static struct snd_kcontrol_new alc260_test_mixer[] = {
 
 	{ } /* end */
 };
-static struct hda_verb alc260_test_init_verbs[] = {
+static const struct hda_verb alc260_test_init_verbs[] = {
 	/* Enable all GPIOs as outputs with an initial value of 0 */
 	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
 	{0x01, AC_VERB_SET_GPIO_DATA, 0x00},
@@ -6907,7 +7176,7 @@ static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
 
 	spec->multiout.num_dacs = 1;
 	spec->multiout.dac_nids = spec->private_dac_nids;
-	spec->multiout.dac_nids[0] = 0x02;
+	spec->private_dac_nids[0] = 0x02;
 
 	nid = cfg->line_out_pins[0];
 	if (nid) {
@@ -7005,7 +7274,7 @@ static void alc260_auto_init_analog_input(struct hda_codec *codec)
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
-static struct hda_verb alc260_volume_init_verbs[] = {
+static const struct hda_verb alc260_volume_init_verbs[] = {
 	/*
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 */
@@ -7050,7 +7319,7 @@ static int alc260_parse_auto_config(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 	int err;
-	static hda_nid_t alc260_ignore[] = { 0x17, 0 };
+	static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
 
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 					   alc260_ignore);
@@ -7095,7 +7364,7 @@ static void alc260_auto_init(struct hda_codec *codec)
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list alc260_loopbacks[] = {
+static const struct hda_amp_list alc260_loopbacks[] = {
 	{ 0x07, HDA_INPUT, 0 },
 	{ 0x07, HDA_INPUT, 1 },
 	{ 0x07, HDA_INPUT, 2 },
@@ -7122,7 +7391,7 @@ static const struct alc_fixup alc260_fixups[] = {
 	},
 };
 
-static struct snd_pci_quirk alc260_fixup_tbl[] = {
+static const struct snd_pci_quirk alc260_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
 	{}
 };
@@ -7146,7 +7415,7 @@ static const char * const alc260_models[ALC260_MODEL_LAST] = {
 	[ALC260_AUTO]		= "auto",
 };
 
-static struct snd_pci_quirk alc260_cfg_tbl[] = {
+static const struct snd_pci_quirk alc260_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
 	SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
 	SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
@@ -7170,7 +7439,7 @@ static struct snd_pci_quirk alc260_cfg_tbl[] = {
 	{}
 };
 
-static struct alc_config_preset alc260_presets[] = {
+static const struct alc_config_preset alc260_presets[] = {
 	[ALC260_BASIC] = {
 		.mixers = { alc260_base_output_mixer,
 			    alc260_input_mixer },
@@ -7195,8 +7464,9 @@ static struct alc_config_preset alc260_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc260_modes),
 		.channel_mode = alc260_modes,
 		.input_mux = &alc260_capture_source,
-		.unsol_event = alc260_hp_unsol_event,
-		.init_hook = alc260_hp_automute,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc260_hp_setup,
+		.init_hook = alc_inithook,
 	},
 	[ALC260_HP_DC7600] = {
 		.mixers = { alc260_hp_dc7600_mixer,
@@ -7210,8 +7480,9 @@ static struct alc_config_preset alc260_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc260_modes),
 		.channel_mode = alc260_modes,
 		.input_mux = &alc260_capture_source,
-		.unsol_event = alc260_hp_3012_unsol_event,
-		.init_hook = alc260_hp_3012_automute,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc260_hp_3012_setup,
+		.init_hook = alc_inithook,
 	},
 	[ALC260_HP_3013] = {
 		.mixers = { alc260_hp_3013_mixer,
@@ -7225,8 +7496,9 @@ static struct alc_config_preset alc260_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc260_modes),
 		.channel_mode = alc260_modes,
 		.input_mux = &alc260_capture_source,
-		.unsol_event = alc260_hp_3013_unsol_event,
-		.init_hook = alc260_hp_3013_automute,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc260_hp_3013_setup,
+		.init_hook = alc_inithook,
 	},
 	[ALC260_FUJITSU_S702X] = {
 		.mixers = { alc260_fujitsu_mixer },
@@ -7384,6 +7656,7 @@ static int patch_alc260(struct hda_codec *codec)
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC260_AUTO)
 		spec->init_hook = alc260_auto_init;
+	spec->shutup = alc_eapd_shutup;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	if (!spec->loopback.amplist)
 		spec->loopback.amplist = alc260_loopbacks;
@@ -7411,12 +7684,12 @@ static int patch_alc260(struct hda_codec *codec)
 #define ALC1200_DIGOUT_NID	0x10
 
 
-static struct hda_channel_mode alc882_ch_modes[1] = {
+static const struct hda_channel_mode alc882_ch_modes[1] = {
 	{ 8, NULL }
 };
 
 /* DACs */
-static hda_nid_t alc882_dac_nids[4] = {
+static const hda_nid_t alc882_dac_nids[4] = {
 	/* front, rear, clfe, rear_surr */
 	0x02, 0x03, 0x04, 0x05
 };
@@ -7426,20 +7699,20 @@ static hda_nid_t alc882_dac_nids[4] = {
 #define alc882_adc_nids		alc880_adc_nids
 #define alc882_adc_nids_alt	alc880_adc_nids_alt
 #define alc883_adc_nids		alc882_adc_nids_alt
-static hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
-static hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
+static const hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
+static const hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
 #define alc889_adc_nids		alc880_adc_nids
 
-static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
-static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
+static const hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
+static const hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
 #define alc883_capsrc_nids	alc882_capsrc_nids_alt
-static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
+static const hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
 #define alc889_capsrc_nids	alc882_capsrc_nids
 
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
 
-static struct hda_input_mux alc882_capture_source = {
+static const struct hda_input_mux alc882_capture_source = {
 	.num_items = 4,
 	.items = {
 		{ "Mic", 0x0 },
@@ -7451,7 +7724,7 @@ static struct hda_input_mux alc882_capture_source = {
 
 #define alc883_capture_source	alc882_capture_source
 
-static struct hda_input_mux alc889_capture_source = {
+static const struct hda_input_mux alc889_capture_source = {
 	.num_items = 3,
 	.items = {
 		{ "Front Mic", 0x0 },
@@ -7460,7 +7733,7 @@ static struct hda_input_mux alc889_capture_source = {
 	},
 };
 
-static struct hda_input_mux mb5_capture_source = {
+static const struct hda_input_mux mb5_capture_source = {
 	.num_items = 3,
 	.items = {
 		{ "Mic", 0x1 },
@@ -7469,7 +7742,7 @@ static struct hda_input_mux mb5_capture_source = {
 	},
 };
 
-static struct hda_input_mux macmini3_capture_source = {
+static const struct hda_input_mux macmini3_capture_source = {
 	.num_items = 2,
 	.items = {
 		{ "Line", 0x2 },
@@ -7477,7 +7750,7 @@ static struct hda_input_mux macmini3_capture_source = {
 	},
 };
 
-static struct hda_input_mux alc883_3stack_6ch_intel = {
+static const struct hda_input_mux alc883_3stack_6ch_intel = {
 	.num_items = 4,
 	.items = {
 		{ "Mic", 0x1 },
@@ -7487,7 +7760,7 @@ static struct hda_input_mux alc883_3stack_6ch_intel = {
 	},
 };
 
-static struct hda_input_mux alc883_lenovo_101e_capture_source = {
+static const struct hda_input_mux alc883_lenovo_101e_capture_source = {
 	.num_items = 2,
 	.items = {
 		{ "Mic", 0x1 },
@@ -7495,7 +7768,7 @@ static struct hda_input_mux alc883_lenovo_101e_capture_source = {
 	},
 };
 
-static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
+static const struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
 	.num_items = 4,
 	.items = {
 		{ "Mic", 0x0 },
@@ -7505,7 +7778,7 @@ static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
 	},
 };
 
-static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
+static const struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
 	.num_items = 2,
 	.items = {
 		{ "Mic", 0x0 },
@@ -7513,7 +7786,7 @@ static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
 	},
 };
 
-static struct hda_input_mux alc883_lenovo_sky_capture_source = {
+static const struct hda_input_mux alc883_lenovo_sky_capture_source = {
 	.num_items = 3,
 	.items = {
 		{ "Mic", 0x0 },
@@ -7522,7 +7795,7 @@ static struct hda_input_mux alc883_lenovo_sky_capture_source = {
 	},
 };
 
-static struct hda_input_mux alc883_asus_eee1601_capture_source = {
+static const struct hda_input_mux alc883_asus_eee1601_capture_source = {
 	.num_items = 2,
 	.items = {
 		{ "Mic", 0x0 },
@@ -7530,7 +7803,7 @@ static struct hda_input_mux alc883_asus_eee1601_capture_source = {
 	},
 };
 
-static struct hda_input_mux alc889A_mb31_capture_source = {
+static const struct hda_input_mux alc889A_mb31_capture_source = {
 	.num_items = 2,
 	.items = {
 		{ "Mic", 0x0 },
@@ -7541,7 +7814,7 @@ static struct hda_input_mux alc889A_mb31_capture_source = {
 	},
 };
 
-static struct hda_input_mux alc889A_imac91_capture_source = {
+static const struct hda_input_mux alc889A_imac91_capture_source = {
 	.num_items = 2,
 	.items = {
 		{ "Mic", 0x01 },
@@ -7552,14 +7825,14 @@ static struct hda_input_mux alc889A_imac91_capture_source = {
 /*
  * 2ch mode
  */
-static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
+static const struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
 	{ 2, NULL }
 };
 
 /*
  * 2ch mode
  */
-static struct hda_verb alc882_3ST_ch2_init[] = {
+static const struct hda_verb alc882_3ST_ch2_init[] = {
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
@@ -7570,7 +7843,7 @@ static struct hda_verb alc882_3ST_ch2_init[] = {
 /*
  * 4ch mode
  */
-static struct hda_verb alc882_3ST_ch4_init[] = {
+static const struct hda_verb alc882_3ST_ch4_init[] = {
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -7582,7 +7855,7 @@ static struct hda_verb alc882_3ST_ch4_init[] = {
 /*
  * 6ch mode
  */
-static struct hda_verb alc882_3ST_ch6_init[] = {
+static const struct hda_verb alc882_3ST_ch6_init[] = {
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
@@ -7592,7 +7865,7 @@ static struct hda_verb alc882_3ST_ch6_init[] = {
 	{ } /* end */
 };
 
-static struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
+static const struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
 	{ 2, alc882_3ST_ch2_init },
 	{ 4, alc882_3ST_ch4_init },
 	{ 6, alc882_3ST_ch6_init },
@@ -7603,7 +7876,7 @@ static struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
 /*
  * 2ch mode
  */
-static struct hda_verb alc883_3ST_ch2_clevo_init[] = {
+static const struct hda_verb alc883_3ST_ch2_clevo_init[] = {
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
@@ -7615,7 +7888,7 @@ static struct hda_verb alc883_3ST_ch2_clevo_init[] = {
 /*
  * 4ch mode
  */
-static struct hda_verb alc883_3ST_ch4_clevo_init[] = {
+static const struct hda_verb alc883_3ST_ch4_clevo_init[] = {
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
@@ -7628,7 +7901,7 @@ static struct hda_verb alc883_3ST_ch4_clevo_init[] = {
 /*
  * 6ch mode
  */
-static struct hda_verb alc883_3ST_ch6_clevo_init[] = {
+static const struct hda_verb alc883_3ST_ch6_clevo_init[] = {
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
@@ -7639,7 +7912,7 @@ static struct hda_verb alc883_3ST_ch6_clevo_init[] = {
 	{ } /* end */
 };
 
-static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
+static const struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
 	{ 2, alc883_3ST_ch2_clevo_init },
 	{ 4, alc883_3ST_ch4_clevo_init },
 	{ 6, alc883_3ST_ch6_clevo_init },
@@ -7649,7 +7922,7 @@ static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
 /*
  * 6ch mode
  */
-static struct hda_verb alc882_sixstack_ch6_init[] = {
+static const struct hda_verb alc882_sixstack_ch6_init[] = {
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -7660,7 +7933,7 @@ static struct hda_verb alc882_sixstack_ch6_init[] = {
 /*
  * 8ch mode
  */
-static struct hda_verb alc882_sixstack_ch8_init[] = {
+static const struct hda_verb alc882_sixstack_ch8_init[] = {
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -7668,7 +7941,7 @@ static struct hda_verb alc882_sixstack_ch8_init[] = {
 	{ } /* end */
 };
 
-static struct hda_channel_mode alc882_sixstack_modes[2] = {
+static const struct hda_channel_mode alc882_sixstack_modes[2] = {
 	{ 6, alc882_sixstack_ch6_init },
 	{ 8, alc882_sixstack_ch8_init },
 };
@@ -7676,7 +7949,7 @@ static struct hda_channel_mode alc882_sixstack_modes[2] = {
 
 /* Macbook Air 2,1 */
 
-static struct hda_channel_mode alc885_mba21_ch_modes[1] = {
+static const struct hda_channel_mode alc885_mba21_ch_modes[1] = {
       { 2, NULL },
 };
 
@@ -7687,7 +7960,7 @@ static struct hda_channel_mode alc885_mba21_ch_modes[1] = {
 /*
  * 2ch mode
  */
-static struct hda_verb alc885_mbp_ch2_init[] = {
+static const struct hda_verb alc885_mbp_ch2_init[] = {
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
@@ -7697,7 +7970,7 @@ static struct hda_verb alc885_mbp_ch2_init[] = {
 /*
  * 4ch mode
  */
-static struct hda_verb alc885_mbp_ch4_init[] = {
+static const struct hda_verb alc885_mbp_ch4_init[] = {
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{ 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
@@ -7706,7 +7979,7 @@ static struct hda_verb alc885_mbp_ch4_init[] = {
 	{ } /* end */
 };
 
-static struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
+static const struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
 	{ 2, alc885_mbp_ch2_init },
 	{ 4, alc885_mbp_ch4_init },
 };
@@ -7716,7 +7989,7 @@ static struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
  * Speakers/Woofer/HP = Front
  * LineIn = Input
  */
-static struct hda_verb alc885_mb5_ch2_init[] = {
+static const struct hda_verb alc885_mb5_ch2_init[] = {
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	{ } /* end */
@@ -7728,14 +8001,14 @@ static struct hda_verb alc885_mb5_ch2_init[] = {
  * Woofer = LFE
  * LineIn = Surround
  */
-static struct hda_verb alc885_mb5_ch6_init[] = {
+static const struct hda_verb alc885_mb5_ch6_init[] = {
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{ } /* end */
 };
 
-static struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
+static const struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
 	{ 2, alc885_mb5_ch2_init },
 	{ 6, alc885_mb5_ch6_init },
 };
@@ -7745,7 +8018,7 @@ static struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
 /*
  * 2ch mode
  */
-static struct hda_verb alc883_4ST_ch2_init[] = {
+static const struct hda_verb alc883_4ST_ch2_init[] = {
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
@@ -7758,7 +8031,7 @@ static struct hda_verb alc883_4ST_ch2_init[] = {
 /*
  * 4ch mode
  */
-static struct hda_verb alc883_4ST_ch4_init[] = {
+static const struct hda_verb alc883_4ST_ch4_init[] = {
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
@@ -7772,7 +8045,7 @@ static struct hda_verb alc883_4ST_ch4_init[] = {
 /*
  * 6ch mode
  */
-static struct hda_verb alc883_4ST_ch6_init[] = {
+static const struct hda_verb alc883_4ST_ch6_init[] = {
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -7787,7 +8060,7 @@ static struct hda_verb alc883_4ST_ch6_init[] = {
 /*
  * 8ch mode
  */
-static struct hda_verb alc883_4ST_ch8_init[] = {
+static const struct hda_verb alc883_4ST_ch8_init[] = {
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
@@ -7800,7 +8073,7 @@ static struct hda_verb alc883_4ST_ch8_init[] = {
 	{ } /* end */
 };
 
-static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
+static const struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
 	{ 2, alc883_4ST_ch2_init },
 	{ 4, alc883_4ST_ch4_init },
 	{ 6, alc883_4ST_ch6_init },
@@ -7811,7 +8084,7 @@ static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
 /*
  * 2ch mode
  */
-static struct hda_verb alc883_3ST_ch2_intel_init[] = {
+static const struct hda_verb alc883_3ST_ch2_intel_init[] = {
 	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
@@ -7822,7 +8095,7 @@ static struct hda_verb alc883_3ST_ch2_intel_init[] = {
 /*
  * 4ch mode
  */
-static struct hda_verb alc883_3ST_ch4_intel_init[] = {
+static const struct hda_verb alc883_3ST_ch4_intel_init[] = {
 	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -7834,7 +8107,7 @@ static struct hda_verb alc883_3ST_ch4_intel_init[] = {
 /*
  * 6ch mode
  */
-static struct hda_verb alc883_3ST_ch6_intel_init[] = {
+static const struct hda_verb alc883_3ST_ch6_intel_init[] = {
 	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
@@ -7844,7 +8117,7 @@ static struct hda_verb alc883_3ST_ch6_intel_init[] = {
 	{ } /* end */
 };
 
-static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
+static const struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
 	{ 2, alc883_3ST_ch2_intel_init },
 	{ 4, alc883_3ST_ch4_intel_init },
 	{ 6, alc883_3ST_ch6_intel_init },
@@ -7853,7 +8126,7 @@ static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
 /*
  * 2ch mode
  */
-static struct hda_verb alc889_ch2_intel_init[] = {
+static const struct hda_verb alc889_ch2_intel_init[] = {
 	{ 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
 	{ 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
 	{ 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
@@ -7866,7 +8139,7 @@ static struct hda_verb alc889_ch2_intel_init[] = {
 /*
  * 6ch mode
  */
-static struct hda_verb alc889_ch6_intel_init[] = {
+static const struct hda_verb alc889_ch6_intel_init[] = {
 	{ 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
 	{ 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
 	{ 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
@@ -7879,7 +8152,7 @@ static struct hda_verb alc889_ch6_intel_init[] = {
 /*
  * 8ch mode
  */
-static struct hda_verb alc889_ch8_intel_init[] = {
+static const struct hda_verb alc889_ch8_intel_init[] = {
 	{ 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
 	{ 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
 	{ 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
@@ -7890,7 +8163,7 @@ static struct hda_verb alc889_ch8_intel_init[] = {
 	{ } /* end */
 };
 
-static struct hda_channel_mode alc889_8ch_intel_modes[3] = {
+static const struct hda_channel_mode alc889_8ch_intel_modes[3] = {
 	{ 2, alc889_ch2_intel_init },
 	{ 6, alc889_ch6_intel_init },
 	{ 8, alc889_ch8_intel_init },
@@ -7899,7 +8172,7 @@ static struct hda_channel_mode alc889_8ch_intel_modes[3] = {
 /*
  * 6ch mode
  */
-static struct hda_verb alc883_sixstack_ch6_init[] = {
+static const struct hda_verb alc883_sixstack_ch6_init[] = {
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -7910,7 +8183,7 @@ static struct hda_verb alc883_sixstack_ch6_init[] = {
 /*
  * 8ch mode
  */
-static struct hda_verb alc883_sixstack_ch8_init[] = {
+static const struct hda_verb alc883_sixstack_ch8_init[] = {
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -7918,7 +8191,7 @@ static struct hda_verb alc883_sixstack_ch8_init[] = {
 	{ } /* end */
 };
 
-static struct hda_channel_mode alc883_sixstack_modes[2] = {
+static const struct hda_channel_mode alc883_sixstack_modes[2] = {
 	{ 6, alc883_sixstack_ch6_init },
 	{ 8, alc883_sixstack_ch8_init },
 };
@@ -7927,7 +8200,7 @@ static struct hda_channel_mode alc883_sixstack_modes[2] = {
 /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
  *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
  */
-static struct snd_kcontrol_new alc882_base_mixer[] = {
+static const struct snd_kcontrol_new alc882_base_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -7954,14 +8227,14 @@ static struct snd_kcontrol_new alc882_base_mixer[] = {
 
 /* Macbook Air 2,1 same control for HP and internal Speaker */
 
-static struct snd_kcontrol_new alc885_mba21_mixer[] = {
+static const struct snd_kcontrol_new alc885_mba21_mixer[] = {
       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
       HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
      { }
 };
 
 
-static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
+static const struct snd_kcontrol_new alc885_mbp3_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
 	HDA_BIND_MUTE   ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
@@ -7976,7 +8249,7 @@ static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc885_mb5_mixer[] = {
+static const struct snd_kcontrol_new alc885_mb5_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
 	HDA_BIND_MUTE   ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
@@ -7994,7 +8267,7 @@ static struct snd_kcontrol_new alc885_mb5_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc885_macmini3_mixer[] = {
+static const struct snd_kcontrol_new alc885_macmini3_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
 	HDA_BIND_MUTE   ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
@@ -8009,14 +8282,14 @@ static struct snd_kcontrol_new alc885_macmini3_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc885_imac91_mixer[] = {
+static const struct snd_kcontrol_new alc885_imac91_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
 	HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
 	{ } /* end */
 };
 
 
-static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
+static const struct snd_kcontrol_new alc882_w2jc_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
@@ -8029,7 +8302,7 @@ static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc882_targa_mixer[] = {
+static const struct snd_kcontrol_new alc882_targa_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
@@ -8049,7 +8322,7 @@ static struct snd_kcontrol_new alc882_targa_mixer[] = {
 /* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
  *                 Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
  */
-static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
+static const struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -8066,7 +8339,7 @@ static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
+static const struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -8080,7 +8353,7 @@ static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc882_chmode_mixer[] = {
+static const struct snd_kcontrol_new alc882_chmode_mixer[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Channel Mode",
@@ -8091,7 +8364,7 @@ static struct snd_kcontrol_new alc882_chmode_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc882_base_init_verbs[] = {
+static const struct hda_verb alc882_base_init_verbs[] = {
 	/* Front mixer: unmute input/output amp left and right (volume = 0) */
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
@@ -8153,7 +8426,7 @@ static struct hda_verb alc882_base_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb alc882_adc1_init_verbs[] = {
+static const struct hda_verb alc882_adc1_init_verbs[] = {
 	/* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
 	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
@@ -8165,26 +8438,26 @@ static struct hda_verb alc882_adc1_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb alc882_eapd_verbs[] = {
+static const struct hda_verb alc882_eapd_verbs[] = {
 	/* change to EAPD mode */
 	{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
 	{0x20, AC_VERB_SET_PROC_COEF, 0x3060},
 	{ }
 };
 
-static struct hda_verb alc889_eapd_verbs[] = {
+static const struct hda_verb alc889_eapd_verbs[] = {
 	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{ }
 };
 
-static struct hda_verb alc_hp15_unsol_verbs[] = {
+static const struct hda_verb alc_hp15_unsol_verbs[] = {
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{}
 };
 
-static struct hda_verb alc885_init_verbs[] = {
+static const struct hda_verb alc885_init_verbs[] = {
 	/* Front mixer: unmute input/output amp left and right (volume = 0) */
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -8243,7 +8516,7 @@ static struct hda_verb alc885_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb alc885_init_input_verbs[] = {
+static const struct hda_verb alc885_init_input_verbs[] = {
 	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
 	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
@@ -8252,7 +8525,7 @@ static struct hda_verb alc885_init_input_verbs[] = {
 
 
 /* Unmute Selector 24h and set the default input to front mic */
-static struct hda_verb alc889_init_input_verbs[] = {
+static const struct hda_verb alc889_init_input_verbs[] = {
 	{0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{ }
@@ -8262,7 +8535,7 @@ static struct hda_verb alc889_init_input_verbs[] = {
 #define alc883_init_verbs	alc882_base_init_verbs
 
 /* Mac Pro test */
-static struct snd_kcontrol_new alc882_macpro_mixer[] = {
+static const struct snd_kcontrol_new alc882_macpro_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
@@ -8275,7 +8548,7 @@ static struct snd_kcontrol_new alc882_macpro_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc882_macpro_init_verbs[] = {
+static const struct hda_verb alc882_macpro_init_verbs[] = {
 	/* Front mixer: unmute input/output amp left and right (volume = 0) */
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
@@ -8327,7 +8600,7 @@ static struct hda_verb alc882_macpro_init_verbs[] = {
 };
 
 /* Macbook 5,1 */
-static struct hda_verb alc885_mb5_init_verbs[] = {
+static const struct hda_verb alc885_mb5_init_verbs[] = {
 	/* DACs */
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -8376,7 +8649,7 @@ static struct hda_verb alc885_mb5_init_verbs[] = {
 };
 
 /* Macmini 3,1 */
-static struct hda_verb alc885_macmini3_init_verbs[] = {
+static const struct hda_verb alc885_macmini3_init_verbs[] = {
 	/* DACs */
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -8423,7 +8696,7 @@ static struct hda_verb alc885_macmini3_init_verbs[] = {
 };
 
 
-static struct hda_verb alc885_mba21_init_verbs[] = {
+static const struct hda_verb alc885_mba21_init_verbs[] = {
 	/*Internal and HP Speaker Mixer*/
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -8446,7 +8719,7 @@ static struct hda_verb alc885_mba21_init_verbs[] = {
 
 
 /* Macbook Pro rev3 */
-static struct hda_verb alc885_mbp3_init_verbs[] = {
+static const struct hda_verb alc885_mbp3_init_verbs[] = {
 	/* Front mixer: unmute input/output amp left and right (volume = 0) */
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
@@ -8510,7 +8783,7 @@ static struct hda_verb alc885_mbp3_init_verbs[] = {
 };
 
 /* iMac 9,1 */
-static struct hda_verb alc885_imac91_init_verbs[] = {
+static const struct hda_verb alc885_imac91_init_verbs[] = {
 	/* Internal Speaker Pin (0x0c) */
 	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -8565,14 +8838,14 @@ static struct hda_verb alc885_imac91_init_verbs[] = {
 };
 
 /* iMac 24 mixer. */
-static struct snd_kcontrol_new alc885_imac24_mixer[] = {
+static const struct snd_kcontrol_new alc885_imac24_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
 	{ } /* end */
 };
 
 /* iMac 24 init verbs. */
-static struct hda_verb alc885_imac24_init_verbs[] = {
+static const struct hda_verb alc885_imac24_init_verbs[] = {
 	/* Internal speakers: output 0 (0x0c) */
 	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -8600,6 +8873,8 @@ static void alc885_imac24_setup(struct hda_codec *codec)
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x18;
 	spec->autocfg.speaker_pins[1] = 0x1a;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 #define alc885_mb5_setup	alc885_imac24_setup
@@ -8612,6 +8887,8 @@ static void alc885_mba21_setup(struct hda_codec *codec)
 
        spec->autocfg.hp_pins[0] = 0x14;
        spec->autocfg.speaker_pins[0] = 0x18;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 
@@ -8622,6 +8899,8 @@ static void alc885_mbp3_setup(struct hda_codec *codec)
 
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 static void alc885_imac91_setup(struct hda_codec *codec)
@@ -8631,9 +8910,11 @@ static void alc885_imac91_setup(struct hda_codec *codec)
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x18;
 	spec->autocfg.speaker_pins[1] = 0x1a;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
-static struct hda_verb alc882_targa_verbs[] = {
+static const struct hda_verb alc882_targa_verbs[] = {
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 
@@ -8652,7 +8933,7 @@ static struct hda_verb alc882_targa_verbs[] = {
 static void alc882_targa_automute(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
-	alc_automute_amp(codec);
+	alc_hp_automute(codec);
 	snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
 				  spec->jack_present ? 1 : 3);
 }
@@ -8663,6 +8944,8 @@ static void alc882_targa_setup(struct hda_codec *codec)
 
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x1b;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
@@ -8671,7 +8954,7 @@ static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
 		alc882_targa_automute(codec);
 }
 
-static struct hda_verb alc882_asus_a7j_verbs[] = {
+static const struct hda_verb alc882_asus_a7j_verbs[] = {
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 
@@ -8689,7 +8972,7 @@ static struct hda_verb alc882_asus_a7j_verbs[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc882_asus_a7m_verbs[] = {
+static const struct hda_verb alc882_asus_a7m_verbs[] = {
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 
@@ -8750,13 +9033,13 @@ static void alc885_macpro_init_hook(struct hda_codec *codec)
 static void alc885_imac24_init_hook(struct hda_codec *codec)
 {
 	alc885_macpro_init_hook(codec);
-	alc_automute_amp(codec);
+	alc_hp_automute(codec);
 }
 
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
-static struct hda_verb alc883_auto_init_verbs[] = {
+static const struct hda_verb alc883_auto_init_verbs[] = {
 	/*
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 */
@@ -8796,7 +9079,7 @@ static struct hda_verb alc883_auto_init_verbs[] = {
 };
 
 /* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
-static struct hda_verb alc889A_mb31_ch2_init[] = {
+static const struct hda_verb alc889A_mb31_ch2_init[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},             /* HP as front */
 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},    /* Line as input */
@@ -8805,7 +9088,7 @@ static struct hda_verb alc889A_mb31_ch2_init[] = {
 };
 
 /* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
-static struct hda_verb alc889A_mb31_ch4_init[] = {
+static const struct hda_verb alc889A_mb31_ch4_init[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},             /* HP as front */
 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},   /* Line as output */
@@ -8814,7 +9097,7 @@ static struct hda_verb alc889A_mb31_ch4_init[] = {
 };
 
 /* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
-static struct hda_verb alc889A_mb31_ch5_init[] = {
+static const struct hda_verb alc889A_mb31_ch5_init[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},             /* HP as rear */
 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},    /* Line as input */
@@ -8823,7 +9106,7 @@ static struct hda_verb alc889A_mb31_ch5_init[] = {
 };
 
 /* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
-static struct hda_verb alc889A_mb31_ch6_init[] = {
+static const struct hda_verb alc889A_mb31_ch6_init[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},             /* HP as front */
 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},   /* Subwoofer off */
 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},   /* Line as output */
@@ -8831,14 +9114,14 @@ static struct hda_verb alc889A_mb31_ch6_init[] = {
 	{ } /* end */
 };
 
-static struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
+static const struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
 	{ 2, alc889A_mb31_ch2_init },
 	{ 4, alc889A_mb31_ch4_init },
 	{ 5, alc889A_mb31_ch5_init },
 	{ 6, alc889A_mb31_ch6_init },
 };
 
-static struct hda_verb alc883_medion_eapd_verbs[] = {
+static const struct hda_verb alc883_medion_eapd_verbs[] = {
         /* eanable EAPD on medion laptop */
 	{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
 	{0x20, AC_VERB_SET_PROC_COEF, 0x3070},
@@ -8847,7 +9130,7 @@ static struct hda_verb alc883_medion_eapd_verbs[] = {
 
 #define alc883_base_mixer	alc882_base_mixer
 
-static struct snd_kcontrol_new alc883_mitac_mixer[] = {
+static const struct snd_kcontrol_new alc883_mitac_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
@@ -8864,7 +9147,7 @@ static struct snd_kcontrol_new alc883_mitac_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
+static const struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -8878,7 +9161,7 @@ static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
+static const struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -8892,7 +9175,7 @@ static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
+static const struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
@@ -8909,7 +9192,7 @@ static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
+static const struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -8932,7 +9215,7 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
+static const struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -8956,7 +9239,7 @@ static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
+static const struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -8980,7 +9263,7 @@ static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
+static const struct snd_kcontrol_new alc883_fivestack_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -9003,7 +9286,7 @@ static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc883_targa_mixer[] = {
+static const struct snd_kcontrol_new alc883_targa_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -9024,7 +9307,7 @@ static struct snd_kcontrol_new alc883_targa_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
+static const struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -9040,7 +9323,7 @@ static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
+static const struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
 	HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
@@ -9049,7 +9332,7 @@ static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
+static const struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -9061,7 +9344,7 @@ static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
+static const struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -9074,7 +9357,7 @@ static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
+static const struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -9084,7 +9367,7 @@ static struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc883_medion_wim2160_verbs[] = {
+static const struct hda_verb alc883_medion_wim2160_verbs[] = {
 	/* Unmute front mixer */
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -9108,9 +9391,11 @@ static void alc883_medion_wim2160_setup(struct hda_codec *codec)
 
 	spec->autocfg.hp_pins[0] = 0x1a;
 	spec->autocfg.speaker_pins[0] = 0x15;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
-static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
+static const struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -9122,7 +9407,7 @@ static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
+static const struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
@@ -9135,7 +9420,7 @@ static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
+static const struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
@@ -9160,7 +9445,7 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc889A_mb31_mixer[] = {
+static const struct snd_kcontrol_new alc889A_mb31_mixer[] = {
 	/* Output mixers */
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
@@ -9186,7 +9471,7 @@ static struct snd_kcontrol_new alc889A_mb31_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc883_vaiott_mixer[] = {
+static const struct snd_kcontrol_new alc883_vaiott_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -9196,7 +9481,7 @@ static struct snd_kcontrol_new alc883_vaiott_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_bind_ctls alc883_bind_cap_vol = {
+static const struct hda_bind_ctls alc883_bind_cap_vol = {
 	.ops = &snd_hda_bind_vol,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
@@ -9205,7 +9490,7 @@ static struct hda_bind_ctls alc883_bind_cap_vol = {
 	},
 };
 
-static struct hda_bind_ctls alc883_bind_cap_switch = {
+static const struct hda_bind_ctls alc883_bind_cap_switch = {
 	.ops = &snd_hda_bind_sw,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
@@ -9214,7 +9499,7 @@ static struct hda_bind_ctls alc883_bind_cap_switch = {
 	},
 };
 
-static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
+static const struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -9226,7 +9511,7 @@ static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
+static const struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
 	HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
 	HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
 	{
@@ -9241,7 +9526,7 @@ static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc883_chmode_mixer[] = {
+static const struct snd_kcontrol_new alc883_chmode_mixer[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Channel Mode",
@@ -9260,9 +9545,11 @@ static void alc883_mitac_setup(struct hda_codec *codec)
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[1] = 0x17;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
-static struct hda_verb alc883_mitac_verbs[] = {
+static const struct hda_verb alc883_mitac_verbs[] = {
 	/* HP */
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -9277,7 +9564,7 @@ static struct hda_verb alc883_mitac_verbs[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc883_clevo_m540r_verbs[] = {
+static const struct hda_verb alc883_clevo_m540r_verbs[] = {
 	/* HP */
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -9293,7 +9580,7 @@ static struct hda_verb alc883_clevo_m540r_verbs[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc883_clevo_m720_verbs[] = {
+static const struct hda_verb alc883_clevo_m720_verbs[] = {
 	/* HP */
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -9308,7 +9595,7 @@ static struct hda_verb alc883_clevo_m720_verbs[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
+static const struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
 	/* HP */
 	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -9322,7 +9609,7 @@ static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc883_targa_verbs[] = {
+static const struct hda_verb alc883_targa_verbs[] = {
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 
@@ -9351,14 +9638,14 @@ static struct hda_verb alc883_targa_verbs[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc883_lenovo_101e_verbs[] = {
+static const struct hda_verb alc883_lenovo_101e_verbs[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
         {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
 	{ } /* end */
 };
 
-static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
+static const struct hda_verb alc883_lenovo_nb0763_verbs[] = {
         {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
         {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
@@ -9366,7 +9653,7 @@ static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
+static const struct hda_verb alc888_lenovo_ms7195_verbs[] = {
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -9375,7 +9662,7 @@ static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc883_haier_w66_verbs[] = {
+static const struct hda_verb alc883_haier_w66_verbs[] = {
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 
@@ -9388,7 +9675,7 @@ static struct hda_verb alc883_haier_w66_verbs[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc888_lenovo_sky_verbs[] = {
+static const struct hda_verb alc888_lenovo_sky_verbs[] = {
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -9400,12 +9687,12 @@ static struct hda_verb alc888_lenovo_sky_verbs[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc888_6st_dell_verbs[] = {
+static const struct hda_verb alc888_6st_dell_verbs[] = {
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
 	{ }
 };
 
-static struct hda_verb alc883_vaiott_verbs[] = {
+static const struct hda_verb alc883_vaiott_verbs[] = {
 	/* HP */
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -9424,9 +9711,11 @@ static void alc888_3st_hp_setup(struct hda_codec *codec)
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[1] = 0x16;
 	spec->autocfg.speaker_pins[2] = 0x18;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
-static struct hda_verb alc888_3st_hp_verbs[] = {
+static const struct hda_verb alc888_3st_hp_verbs[] = {
 	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},	/* Front: output 0 (0x0c) */
 	{0x16, AC_VERB_SET_CONNECT_SEL, 0x01},	/* Rear : output 1 (0x0d) */
 	{0x18, AC_VERB_SET_CONNECT_SEL, 0x02},	/* CLFE : output 2 (0x0e) */
@@ -9437,7 +9726,7 @@ static struct hda_verb alc888_3st_hp_verbs[] = {
 /*
  * 2ch mode
  */
-static struct hda_verb alc888_3st_hp_2ch_init[] = {
+static const struct hda_verb alc888_3st_hp_2ch_init[] = {
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
@@ -9448,7 +9737,7 @@ static struct hda_verb alc888_3st_hp_2ch_init[] = {
 /*
  * 4ch mode
  */
-static struct hda_verb alc888_3st_hp_4ch_init[] = {
+static const struct hda_verb alc888_3st_hp_4ch_init[] = {
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -9460,7 +9749,7 @@ static struct hda_verb alc888_3st_hp_4ch_init[] = {
 /*
  * 6ch mode
  */
-static struct hda_verb alc888_3st_hp_6ch_init[] = {
+static const struct hda_verb alc888_3st_hp_6ch_init[] = {
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
@@ -9470,39 +9759,21 @@ static struct hda_verb alc888_3st_hp_6ch_init[] = {
 	{ } /* end */
 };
 
-static struct hda_channel_mode alc888_3st_hp_modes[3] = {
+static const struct hda_channel_mode alc888_3st_hp_modes[3] = {
 	{ 2, alc888_3st_hp_2ch_init },
 	{ 4, alc888_3st_hp_4ch_init },
 	{ 6, alc888_3st_hp_6ch_init },
 };
 
-/* toggle front-jack and RCA according to the hp-jack state */
-static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
+static void alc888_lenovo_ms7195_setup(struct hda_codec *codec)
 {
- 	unsigned int present = snd_hda_jack_detect(codec, 0x1b);
-
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-}
-
-/* toggle RCA according to the front-jack state */
-static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
-{
- 	unsigned int present = snd_hda_jack_detect(codec, 0x14);
-
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-}
+	struct alc_spec *spec = codec->spec;
 
-static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
-					     unsigned int res)
-{
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc888_lenovo_ms7195_front_automute(codec);
-	if ((res >> 26) == ALC880_FRONT_EVENT)
-		alc888_lenovo_ms7195_rca_automute(codec);
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.line_out_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[0] = 0x15;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 /* toggle speaker-output according to the hp-jack state */
@@ -9512,6 +9783,8 @@ static void alc883_lenovo_nb0763_setup(struct hda_codec *codec)
 
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x15;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 /* toggle speaker-output according to the hp-jack state */
@@ -9524,11 +9797,13 @@ static void alc883_clevo_m720_setup(struct hda_codec *codec)
 
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
 {
-	alc_automute_amp(codec);
+	alc_hp_automute(codec);
 	alc88x_simple_mic_automute(codec);
 }
 
@@ -9540,7 +9815,7 @@ static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
 		alc88x_simple_mic_automute(codec);
 		break;
 	default:
-		alc_automute_amp_unsol_event(codec, res);
+		alc_sku_unsol_event(codec, res);
 		break;
 	}
 }
@@ -9552,6 +9827,8 @@ static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
 
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x15;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 static void alc883_haier_w66_setup(struct hda_codec *codec)
@@ -9560,33 +9837,21 @@ static void alc883_haier_w66_setup(struct hda_codec *codec)
 
 	spec->autocfg.hp_pins[0] = 0x1b;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
-static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
+static void alc883_lenovo_101e_setup(struct hda_codec *codec)
 {
-	int bits = snd_hda_jack_detect(codec, 0x14) ? HDA_AMP_MUTE : 0;
-
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-}
-
-static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
-{
-	int bits = snd_hda_jack_detect(codec, 0x1b) ? HDA_AMP_MUTE : 0;
-
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-}
+	struct alc_spec *spec = codec->spec;
 
-static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
-{
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc883_lenovo_101e_all_automute(codec);
-	if ((res >> 26) == ALC880_FRONT_EVENT)
-		alc883_lenovo_101e_ispeaker_automute(codec);
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.line_out_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[0] = 0x15;
+	spec->automute = 1;
+	spec->detect_line = 1;
+	spec->automute_lines = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 /* toggle speaker-output according to the hp-jack state */
@@ -9597,9 +9862,11 @@ static void alc883_acer_aspire_setup(struct hda_codec *codec)
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[1] = 0x16;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
-static struct hda_verb alc883_acer_eapd_verbs[] = {
+static const struct hda_verb alc883_acer_eapd_verbs[] = {
 	/* HP Pin: output 0 (0x0c) */
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -9626,6 +9893,8 @@ static void alc888_6st_dell_setup(struct hda_codec *codec)
 	spec->autocfg.speaker_pins[1] = 0x15;
 	spec->autocfg.speaker_pins[2] = 0x16;
 	spec->autocfg.speaker_pins[3] = 0x17;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 static void alc888_lenovo_sky_setup(struct hda_codec *codec)
@@ -9638,6 +9907,8 @@ static void alc888_lenovo_sky_setup(struct hda_codec *codec)
 	spec->autocfg.speaker_pins[2] = 0x16;
 	spec->autocfg.speaker_pins[3] = 0x17;
 	spec->autocfg.speaker_pins[4] = 0x1a;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 static void alc883_vaiott_setup(struct hda_codec *codec)
@@ -9647,9 +9918,11 @@ static void alc883_vaiott_setup(struct hda_codec *codec)
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[1] = 0x17;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
-static struct hda_verb alc888_asus_m90v_verbs[] = {
+static const struct hda_verb alc888_asus_m90v_verbs[] = {
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -9672,9 +9945,11 @@ static void alc883_mode2_setup(struct hda_codec *codec)
 	spec->ext_mic.mux_idx = 0;
 	spec->int_mic.mux_idx = 1;
 	spec->auto_mic = 1;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
-static struct hda_verb alc888_asus_eee1601_verbs[] = {
+static const struct hda_verb alc888_asus_eee1601_verbs[] = {
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
@@ -9693,10 +9968,10 @@ static void alc883_eee1601_inithook(struct hda_codec *codec)
 
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x1b;
-	alc_automute_pin(codec);
+	alc_hp_automute(codec);
 }
 
-static struct hda_verb alc889A_mb31_verbs[] = {
+static const struct hda_verb alc889A_mb31_verbs[] = {
 	/* Init rear pin (used as headphone output) */
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},    /* Apple Headphones */
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},           /* Connect to front */
@@ -9742,11 +10017,11 @@ static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
 #define alc882_pcm_digital_playback	alc880_pcm_digital_playback
 #define alc882_pcm_digital_capture	alc880_pcm_digital_capture
 
-static hda_nid_t alc883_slave_dig_outs[] = {
+static const hda_nid_t alc883_slave_dig_outs[] = {
 	ALC1200_DIGOUT_NID, 0,
 };
 
-static hda_nid_t alc1200_slave_dig_outs[] = {
+static const hda_nid_t alc1200_slave_dig_outs[] = {
 	ALC883_DIGOUT_NID, 0,
 };
 
@@ -9805,7 +10080,7 @@ static const char * const alc882_models[ALC882_MODEL_LAST] = {
 	[ALC882_AUTO]		= "auto",
 };
 
-static struct snd_pci_quirk alc882_cfg_tbl[] = {
+static const struct snd_pci_quirk alc882_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
 
 	SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
@@ -9932,7 +10207,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = {
 };
 
 /* codec SSID table for Intel Mac */
-static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
+static const struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
 	SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
 	SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
@@ -9959,7 +10234,7 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
 	{} /* terminator */
 };
 
-static struct alc_config_preset alc882_presets[] = {
+static const struct alc_config_preset alc882_presets[] = {
 	[ALC882_3ST_DIG] = {
 		.mixers = { alc882_base_mixer },
 		.init_verbs = { alc882_base_init_verbs,
@@ -10015,9 +10290,9 @@ static struct alc_config_preset alc882_presets[] = {
 			.channel_mode = alc885_mba21_ch_modes,
 			.num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
 			.input_mux = &alc882_capture_source,
-			.unsol_event = alc_automute_amp_unsol_event,
+			.unsol_event = alc_sku_unsol_event,
 			.setup = alc885_mba21_setup,
-			.init_hook = alc_automute_amp,
+			.init_hook = alc_hp_automute,
        },
 	[ALC885_MBP3] = {
 		.mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
@@ -10031,9 +10306,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.input_mux = &alc882_capture_source,
 		.dig_out_nid = ALC882_DIGOUT_NID,
 		.dig_in_nid = ALC882_DIGIN_NID,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc885_mbp3_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC885_MB5] = {
 		.mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
@@ -10046,9 +10321,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.input_mux = &mb5_capture_source,
 		.dig_out_nid = ALC882_DIGOUT_NID,
 		.dig_in_nid = ALC882_DIGIN_NID,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc885_mb5_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC885_MACMINI3] = {
 		.mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
@@ -10061,9 +10336,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.input_mux = &macmini3_capture_source,
 		.dig_out_nid = ALC882_DIGOUT_NID,
 		.dig_in_nid = ALC882_DIGIN_NID,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc885_macmini3_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC885_MACPRO] = {
 		.mixers = { alc882_macpro_mixer },
@@ -10087,7 +10362,7 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
 		.channel_mode = alc882_ch_modes,
 		.input_mux = &alc882_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc885_imac24_setup,
 		.init_hook = alc885_imac24_init_hook,
 	},
@@ -10102,9 +10377,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.input_mux = &alc889A_imac91_capture_source,
 		.dig_out_nid = ALC882_DIGOUT_NID,
 		.dig_in_nid = ALC882_DIGIN_NID,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc885_imac91_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC882_TARGA] = {
 		.mixers = { alc882_targa_mixer, alc882_chmode_mixer },
@@ -10120,7 +10395,7 @@ static struct alc_config_preset alc882_presets[] = {
 		.channel_mode = alc882_3ST_6ch_modes,
 		.need_dac_fix = 1,
 		.input_mux = &alc882_capture_source,
-		.unsol_event = alc882_targa_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc882_targa_setup,
 		.init_hook = alc882_targa_automute,
 	},
@@ -10214,8 +10489,8 @@ static struct alc_config_preset alc882_presets[] = {
 		.capsrc_nids = alc889_capsrc_nids,
 		.input_mux = &alc889_capture_source,
 		.setup = alc889_automute_setup,
-		.init_hook = alc_automute_amp,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.init_hook = alc_hp_automute,
+		.unsol_event = alc_sku_unsol_event,
 		.need_dac_fix = 1,
 	},
 	[ALC889_INTEL] = {
@@ -10235,7 +10510,7 @@ static struct alc_config_preset alc882_presets[] = {
 		.input_mux = &alc889_capture_source,
 		.setup = alc889_automute_setup,
 		.init_hook = alc889_intel_init_hook,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.need_dac_fix = 1,
 	},
 	[ALC883_6ST_DIG] = {
@@ -10324,9 +10599,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc883_acer_aspire_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC888_ACER_ASPIRE_4930G] = {
 		.mixers = { alc888_acer_aspire_4930g_mixer,
@@ -10346,9 +10621,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_mux_defs =
 			ARRAY_SIZE(alc888_2_capture_sources),
 		.input_mux = alc888_2_capture_sources,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc888_acer_aspire_4930g_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC888_ACER_ASPIRE_6530G] = {
 		.mixers = { alc888_acer_aspire_6530_mixer },
@@ -10365,9 +10640,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_mux_defs =
 			ARRAY_SIZE(alc888_2_capture_sources),
 		.input_mux = alc888_acer_aspire_6530_sources,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc888_acer_aspire_6530g_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC888_ACER_ASPIRE_8930G] = {
 		.mixers = { alc889_acer_aspire_8930g_mixer,
@@ -10388,9 +10663,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_mux_defs =
 			ARRAY_SIZE(alc889_capture_sources),
 		.input_mux = alc889_capture_sources,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc889_acer_aspire_8930g_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 		.power_hook = alc_power_eapd,
 #endif
@@ -10411,9 +10686,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.need_dac_fix = 1,
 		.const_channel_count = 6,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc888_acer_aspire_7730g_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC883_MEDION] = {
 		.mixers = { alc883_fivestack_mixer,
@@ -10440,9 +10715,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc883_medion_wim2160_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC883_LAPTOP_EAPD] = {
 		.mixers = { alc883_base_mixer },
@@ -10492,8 +10767,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_lenovo_101e_capture_source,
-		.unsol_event = alc883_lenovo_101e_unsol_event,
-		.init_hook = alc883_lenovo_101e_all_automute,
+		.setup = alc883_lenovo_101e_setup,
+		.unsol_event = alc_sku_unsol_event,
+		.init_hook = alc_inithook,
 	},
 	[ALC883_LENOVO_NB0763] = {
 		.mixers = { alc883_lenovo_nb0763_mixer },
@@ -10504,9 +10780,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.channel_mode = alc883_3ST_2ch_modes,
 		.need_dac_fix = 1,
 		.input_mux = &alc883_lenovo_nb0763_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc883_lenovo_nb0763_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC888_LENOVO_MS7195_DIG] = {
 		.mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
@@ -10518,8 +10794,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.channel_mode = alc883_3ST_6ch_modes,
 		.need_dac_fix = 1,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc883_lenovo_ms7195_unsol_event,
-		.init_hook = alc888_lenovo_ms7195_front_automute,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc888_lenovo_ms7195_setup,
+		.init_hook = alc_inithook,
 	},
 	[ALC883_HAIER_W66] = {
 		.mixers = { alc883_targa_2ch_mixer},
@@ -10530,9 +10807,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc883_haier_w66_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC888_3ST_HP] = {
 		.mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
@@ -10543,9 +10820,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.channel_mode = alc888_3st_hp_modes,
 		.need_dac_fix = 1,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc888_3st_hp_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC888_6ST_DELL] = {
 		.mixers = { alc883_base_mixer, alc883_chmode_mixer },
@@ -10557,9 +10834,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
 		.channel_mode = alc883_sixstack_modes,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc888_6st_dell_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC883_MITAC] = {
 		.mixers = { alc883_mitac_mixer },
@@ -10569,9 +10846,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc883_mitac_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC883_FUJITSU_PI2515] = {
 		.mixers = { alc883_2ch_fujitsu_pi2515_mixer },
@@ -10583,9 +10860,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_fujitsu_pi2515_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc883_2ch_fujitsu_pi2515_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC888_FUJITSU_XA3530] = {
 		.mixers = { alc888_base_mixer, alc883_chmode_mixer },
@@ -10602,9 +10879,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_mux_defs =
 			ARRAY_SIZE(alc888_2_capture_sources),
 		.input_mux = alc888_2_capture_sources,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc888_fujitsu_xa3530_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC888_LENOVO_SKY] = {
 		.mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
@@ -10616,9 +10893,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.channel_mode = alc883_sixstack_modes,
 		.need_dac_fix = 1,
 		.input_mux = &alc883_lenovo_sky_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc888_lenovo_sky_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC888_ASUS_M90V] = {
 		.mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
@@ -10686,9 +10963,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc883_vaiott_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 };
 
@@ -10734,7 +11011,7 @@ static const struct alc_fixup alc882_fixups[] = {
 	},
 };
 
-static struct snd_pci_quirk alc882_fixup_tbl[] = {
+static const struct snd_pci_quirk alc882_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
 	SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530),
 	SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
@@ -10842,6 +11119,11 @@ static void alc882_auto_init_input_src(struct hda_codec *codec)
 		const struct hda_input_mux *imux;
 		int conns, mute, idx, item;
 
+		/* mute ADC */
+		snd_hda_codec_write(codec, spec->adc_nids[c], 0,
+				    AC_VERB_SET_AMP_GAIN_MUTE,
+				    AMP_IN_MUTE(0));
+
 		conns = snd_hda_get_connections(codec, nid, conn_list,
 						ARRAY_SIZE(conn_list));
 		if (conns < 0)
@@ -10921,7 +11203,7 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec)
 static int alc882_parse_auto_config(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
-	static hda_nid_t alc882_ignore[] = { 0x1d, 0 };
+	static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
 	int err;
 
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
@@ -10934,6 +11216,9 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
 	err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
 	if (err < 0)
 		return err;
+	err = alc_auto_add_multi_channel_mode(codec);
+	if (err < 0)
+		return err;
 	err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
 	if (err < 0)
 		return err;
@@ -11135,14 +11420,14 @@ static int patch_alc882(struct hda_codec *codec)
 #define alc262_modes		alc260_modes
 #define alc262_capture_source	alc882_capture_source
 
-static hda_nid_t alc262_dmic_adc_nids[1] = {
+static const hda_nid_t alc262_dmic_adc_nids[1] = {
 	/* ADC0 */
 	0x09
 };
 
-static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
+static const hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
 
-static struct snd_kcontrol_new alc262_base_mixer[] = {
+static const struct snd_kcontrol_new alc262_base_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
@@ -11163,71 +11448,30 @@ static struct snd_kcontrol_new alc262_base_mixer[] = {
 };
 
 /* update HP, line and mono-out pins according to the master switch */
-static void alc262_hp_master_update(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-	int val = spec->master_sw;
-
-	/* HP & line-out */
-	snd_hda_codec_write_cache(codec, 0x1b, 0,
-				  AC_VERB_SET_PIN_WIDGET_CONTROL,
-				  val ? PIN_HP : 0);
-	snd_hda_codec_write_cache(codec, 0x15, 0,
-				  AC_VERB_SET_PIN_WIDGET_CONTROL,
-				  val ? PIN_HP : 0);
-	/* mono (speaker) depending on the HP jack sense */
-	val = val && !spec->jack_present;
-	snd_hda_codec_write_cache(codec, 0x16, 0,
-				  AC_VERB_SET_PIN_WIDGET_CONTROL,
-				  val ? PIN_OUT : 0);
-}
+#define alc262_hp_master_update		alc260_hp_master_update
 
-static void alc262_hp_bpc_automute(struct hda_codec *codec)
+static void alc262_hp_bpc_setup(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 
-	spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
-	alc262_hp_master_update(codec);
-}
-
-static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-	if ((res >> 26) != ALC880_HP_EVENT)
-		return;
-	alc262_hp_bpc_automute(codec);
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.speaker_pins[0] = 0x16;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
 }
 
-static void alc262_hp_wildwest_automute(struct hda_codec *codec)
+static void alc262_hp_wildwest_setup(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 
-	spec->jack_present = snd_hda_jack_detect(codec, 0x15);
-	alc262_hp_master_update(codec);
-}
-
-static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
-{
-	if ((res >> 26) != ALC880_HP_EVENT)
-		return;
-	alc262_hp_wildwest_automute(codec);
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x16;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
 }
 
 #define alc262_hp_master_sw_get		alc260_hp_master_sw_get
-
-static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
-				   struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct alc_spec *spec = codec->spec;
-	int val = !!*ucontrol->value.integer.value;
-
-	if (val == spec->master_sw)
-		return 0;
-	spec->master_sw = val;
-	alc262_hp_master_update(codec);
-	return 1;
-}
+#define alc262_hp_master_sw_put		alc260_hp_master_sw_put
 
 #define ALC262_HP_MASTER_SWITCH					\
 	{							\
@@ -11244,7 +11488,7 @@ static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
 	}
 
 
-static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
+static const struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
 	ALC262_HP_MASTER_SWITCH,
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -11268,7 +11512,7 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
+static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
 	ALC262_HP_MASTER_SWITCH,
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
@@ -11288,7 +11532,7 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
+static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
 	HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT),
@@ -11302,9 +11546,11 @@ static void alc262_hp_t5735_setup(struct hda_codec *codec)
 
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
 }
 
-static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
+static const struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -11315,7 +11561,7 @@ static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc262_hp_t5735_verbs[] = {
+static const struct hda_verb alc262_hp_t5735_verbs[] = {
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 
@@ -11323,7 +11569,7 @@ static struct hda_verb alc262_hp_t5735_verbs[] = {
 	{ }
 };
 
-static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
+static const struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
@@ -11333,7 +11579,7 @@ static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc262_hp_rp5700_verbs[] = {
+static const struct hda_verb alc262_hp_rp5700_verbs[] = {
 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
@@ -11347,7 +11593,7 @@ static struct hda_verb alc262_hp_rp5700_verbs[] = {
 	{}
 };
 
-static struct hda_input_mux alc262_hp_rp5700_capture_source = {
+static const struct hda_input_mux alc262_hp_rp5700_capture_source = {
 	.num_items = 1,
 	.items = {
 		{ "Line", 0x1 },
@@ -11355,44 +11601,9 @@ static struct hda_input_mux alc262_hp_rp5700_capture_source = {
 };
 
 /* bind hp and internal speaker mute (with plug check) as master switch */
-static void alc262_hippo_master_update(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-	hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
-	hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
-	hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
-	unsigned int mute;
-
-	/* HP */
-	mute = spec->master_sw ? 0 : HDA_AMP_MUTE;
-	snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, mute);
-	/* mute internal speaker per jack sense */
-	if (spec->jack_present)
-		mute = HDA_AMP_MUTE;
-	if (line_nid)
-		snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
-	if (speaker_nid && speaker_nid != line_nid)
-		snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
-}
-
+#define alc262_hippo_master_update	alc262_hp_master_update
 #define alc262_hippo_master_sw_get	alc262_hp_master_sw_get
-
-static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
-				      struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct alc_spec *spec = codec->spec;
-	int val = !!*ucontrol->value.integer.value;
-
-	if (val == spec->master_sw)
-		return 0;
-	spec->master_sw = val;
-	alc262_hippo_master_update(codec);
-	return 1;
-}
+#define alc262_hippo_master_sw_put	alc262_hp_master_sw_put
 
 #define ALC262_HIPPO_MASTER_SWITCH				\
 	{							\
@@ -11409,7 +11620,7 @@ static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
 			     (SUBDEV_SPEAKER(0) << 16), \
 	}
 
-static struct snd_kcontrol_new alc262_hippo_mixer[] = {
+static const struct snd_kcontrol_new alc262_hippo_mixer[] = {
 	ALC262_HIPPO_MASTER_SWITCH,
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
@@ -11426,7 +11637,7 @@ static struct snd_kcontrol_new alc262_hippo_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
+static const struct snd_kcontrol_new alc262_hippo1_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	ALC262_HIPPO_MASTER_SWITCH,
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
@@ -11443,28 +11654,14 @@ static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
 };
 
 /* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc262_hippo_automute(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-	hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
-
-	spec->jack_present = snd_hda_jack_detect(codec, hp_nid);
-	alc262_hippo_master_update(codec);
-}
-
-static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-	if ((res >> 26) != ALC880_HP_EVENT)
-		return;
-	alc262_hippo_automute(codec);
-}
-
 static void alc262_hippo_setup(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 static void alc262_hippo1_setup(struct hda_codec *codec)
@@ -11473,10 +11670,12 @@ static void alc262_hippo1_setup(struct hda_codec *codec)
 
 	spec->autocfg.hp_pins[0] = 0x1b;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 
-static struct snd_kcontrol_new alc262_sony_mixer[] = {
+static const struct snd_kcontrol_new alc262_sony_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	ALC262_HIPPO_MASTER_SWITCH,
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -11486,7 +11685,7 @@ static struct snd_kcontrol_new alc262_sony_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
+static const struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	ALC262_HIPPO_MASTER_SWITCH,
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -11497,7 +11696,7 @@ static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc262_tyan_mixer[] = {
+static const struct snd_kcontrol_new alc262_tyan_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
@@ -11513,7 +11712,7 @@ static struct snd_kcontrol_new alc262_tyan_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc262_tyan_verbs[] = {
+static const struct hda_verb alc262_tyan_verbs[] = {
 	/* Headphone automute */
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -11535,6 +11734,8 @@ static void alc262_tyan_setup(struct hda_codec *codec)
 
 	spec->autocfg.hp_pins[0] = 0x1b;
 	spec->autocfg.speaker_pins[0] = 0x15;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 
@@ -11544,7 +11745,7 @@ static void alc262_tyan_setup(struct hda_codec *codec)
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
-static struct hda_verb alc262_init_verbs[] = {
+static const struct hda_verb alc262_init_verbs[] = {
 	/*
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 */
@@ -11620,13 +11821,13 @@ static struct hda_verb alc262_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb alc262_eapd_verbs[] = {
+static const struct hda_verb alc262_eapd_verbs[] = {
 	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{ }
 };
 
-static struct hda_verb alc262_hippo1_unsol_verbs[] = {
+static const struct hda_verb alc262_hippo1_unsol_verbs[] = {
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
 	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
@@ -11636,7 +11837,7 @@ static struct hda_verb alc262_hippo1_unsol_verbs[] = {
 	{}
 };
 
-static struct hda_verb alc262_sony_unsol_verbs[] = {
+static const struct hda_verb alc262_sony_unsol_verbs[] = {
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},	// Front Mic
@@ -11646,7 +11847,7 @@ static struct hda_verb alc262_sony_unsol_verbs[] = {
 	{}
 };
 
-static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
+static const struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -11655,7 +11856,7 @@ static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc262_toshiba_s06_verbs[] = {
+static const struct hda_verb alc262_toshiba_s06_verbs[] = {
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -11678,6 +11879,8 @@ static void alc262_toshiba_s06_setup(struct hda_codec *codec)
 	spec->int_mic.pin = 0x12;
 	spec->int_mic.mux_idx = 9;
 	spec->auto_mic = 1;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
 }
 
 /*
@@ -11687,7 +11890,7 @@ static void alc262_toshiba_s06_setup(struct hda_codec *codec)
  *  0x18 = external mic
  */
 
-static struct snd_kcontrol_new alc262_nec_mixer[] = {
+static const struct snd_kcontrol_new alc262_nec_mixer[] = {
 	HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
 
@@ -11700,7 +11903,7 @@ static struct snd_kcontrol_new alc262_nec_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc262_nec_verbs[] = {
+static const struct hda_verb alc262_nec_verbs[] = {
 	/* Unmute Speaker */
 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 
@@ -11723,7 +11926,7 @@ static struct hda_verb alc262_nec_verbs[] = {
 
 #define ALC_HP_EVENT	0x37
 
-static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
+static const struct hda_verb alc262_fujitsu_unsol_verbs[] = {
 	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
@@ -11731,20 +11934,20 @@ static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
 	{}
 };
 
-static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
+static const struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{}
 };
 
-static struct hda_verb alc262_lenovo_3000_init_verbs[] = {
+static const struct hda_verb alc262_lenovo_3000_init_verbs[] = {
 	/* Front Mic pin: input vref at 50% */
 	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
 	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	{}
 };
 
-static struct hda_input_mux alc262_fujitsu_capture_source = {
+static const struct hda_input_mux alc262_fujitsu_capture_source = {
 	.num_items = 3,
 	.items = {
 		{ "Mic", 0x0 },
@@ -11753,7 +11956,7 @@ static struct hda_input_mux alc262_fujitsu_capture_source = {
 	},
 };
 
-static struct hda_input_mux alc262_HP_capture_source = {
+static const struct hda_input_mux alc262_HP_capture_source = {
 	.num_items = 5,
 	.items = {
 		{ "Mic", 0x0 },
@@ -11764,7 +11967,7 @@ static struct hda_input_mux alc262_HP_capture_source = {
 	},
 };
 
-static struct hda_input_mux alc262_HP_D7000_capture_source = {
+static const struct hda_input_mux alc262_HP_D7000_capture_source = {
 	.num_items = 4,
 	.items = {
 		{ "Mic", 0x0 },
@@ -11774,44 +11977,19 @@ static struct hda_input_mux alc262_HP_D7000_capture_source = {
 	},
 };
 
-/* mute/unmute internal speaker according to the hp jacks and mute state */
-static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
+static void alc262_fujitsu_setup(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
-	unsigned int mute;
-
-	if (force || !spec->sense_updated) {
-		spec->jack_present = snd_hda_jack_detect(codec, 0x14) ||
-				     snd_hda_jack_detect(codec, 0x1b);
-		spec->sense_updated = 1;
-	}
-	/* unmute internal speaker only if both HPs are unplugged and
-	 * master switch is on
-	 */
-	if (spec->jack_present)
-		mute = HDA_AMP_MUTE;
-	else
-		mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, mute);
-}
-
-/* unsolicited event for HP jack sensing */
-static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
-				       unsigned int res)
-{
-	if ((res >> 26) != ALC_HP_EVENT)
-		return;
-	alc262_fujitsu_automute(codec, 1);
-}
 
-static void alc262_fujitsu_init_hook(struct hda_codec *codec)
-{
-	alc262_fujitsu_automute(codec, 1);
+	spec->autocfg.hp_pins[0] = 0x14;
+	spec->autocfg.hp_pins[1] = 0x1b;
+	spec->autocfg.speaker_pins[0] = 0x15;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 /* bind volumes of both NID 0x0c and 0x0d */
-static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
+static const struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
 	.ops = &snd_hda_bind_vol,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
@@ -11820,78 +11998,15 @@ static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
 	},
 };
 
-/* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
-{
-	struct alc_spec *spec = codec->spec;
-	unsigned int mute;
-
-	if (force || !spec->sense_updated) {
-		spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
-		spec->sense_updated = 1;
-	}
-	if (spec->jack_present) {
-		/* mute internal speaker */
-		snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
-		snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
-	} else {
-		/* unmute internal speaker if necessary */
-		mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
-		snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
-		snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
-	}
-}
-
-/* unsolicited event for HP jack sensing */
-static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
-				       unsigned int res)
-{
-	if ((res >> 26) != ALC_HP_EVENT)
-		return;
-	alc262_lenovo_3000_automute(codec, 1);
-}
-
-static int amp_stereo_mute_update(struct hda_codec *codec, hda_nid_t nid,
-				  int dir, int idx, long *valp)
-{
-	int i, change = 0;
-
-	for (i = 0; i < 2; i++, valp++)
-		change |= snd_hda_codec_amp_update(codec, nid, i, dir, idx,
-						   HDA_AMP_MUTE,
-						   *valp ? 0 : HDA_AMP_MUTE);
-	return change;
-}
-
-/* bind hp and internal speaker mute (with plug check) */
-static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
-					 struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	long *valp = ucontrol->value.integer.value;
-	int change;
-
-	change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
-	change |= amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
-	if (change)
-		alc262_fujitsu_automute(codec, 0);
-	return change;
-}
-
-static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
+static const struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
 	HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
-		.subdevice = HDA_SUBDEV_AMP_FLAG,
-		.info = snd_hda_mixer_amp_switch_info,
-		.get = snd_hda_mixer_amp_switch_get,
-		.put = alc262_fujitsu_master_sw_put,
-		.private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+		.subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
+		.info = snd_ctl_boolean_mono_info,
+		.get = alc262_hp_master_sw_get,
+		.put = alc262_hp_master_sw_put,
 	},
 	{
 		.iface = NID_MAPPING,
@@ -11909,30 +12024,26 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
 	{ } /* end */
 };
 
-/* bind hp and internal speaker mute (with plug check) */
-static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
-					 struct snd_ctl_elem_value *ucontrol)
+static void alc262_lenovo_3000_setup(struct hda_codec *codec)
 {
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	long *valp = ucontrol->value.integer.value;
-	int change;
+	struct alc_spec *spec = codec->spec;
 
-	change = amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
-	if (change)
-		alc262_lenovo_3000_automute(codec, 0);
-	return change;
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[1] = 0x16;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
-static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
+static const struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
 	HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
-		.subdevice = HDA_SUBDEV_AMP_FLAG,
-		.info = snd_hda_mixer_amp_switch_info,
-		.get = snd_hda_mixer_amp_switch_get,
-		.put = alc262_lenovo_3000_master_sw_put,
-		.private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
+		.subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
+		.info = snd_ctl_boolean_mono_info,
+		.get = alc262_hp_master_sw_get,
+		.put = alc262_hp_master_sw_put,
 	},
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
@@ -11945,7 +12056,7 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
+static const struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
 	HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
 	ALC262_HIPPO_MASTER_SWITCH,
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -11958,13 +12069,13 @@ static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
 };
 
 /* additional init verbs for Benq laptops */
-static struct hda_verb alc262_EAPD_verbs[] = {
+static const struct hda_verb alc262_EAPD_verbs[] = {
 	{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
 	{0x20, AC_VERB_SET_PROC_COEF,  0x3070},
 	{}
 };
 
-static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
+static const struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
 
@@ -11974,7 +12085,7 @@ static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
 };
 
 /* Samsung Q1 Ultra Vista model setup */
-static struct snd_kcontrol_new alc262_ultra_mixer[] = {
+static const struct snd_kcontrol_new alc262_ultra_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
@@ -11984,7 +12095,7 @@ static struct snd_kcontrol_new alc262_ultra_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc262_ultra_verbs[] = {
+static const struct hda_verb alc262_ultra_verbs[] = {
 	/* output mixer */
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
@@ -12047,7 +12158,7 @@ static void alc262_ultra_unsol_event(struct hda_codec *codec,
 	alc262_ultra_automute(codec);
 }
 
-static struct hda_input_mux alc262_ultra_capture_source = {
+static const struct hda_input_mux alc262_ultra_capture_source = {
 	.num_items = 2,
 	.items = {
 		{ "Mic", 0x1 },
@@ -12073,7 +12184,7 @@ static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
 	return ret;
 }
 
-static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
+static const struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
 	{
@@ -12148,9 +12259,9 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
 
 	spec->multiout.num_dacs = 1;	/* only use one dac */
 	spec->multiout.dac_nids = spec->private_dac_nids;
-	spec->multiout.dac_nids[0] = 2;
+	spec->private_dac_nids[0] = 2;
 
-	pfx = alc_get_line_out_pfx(cfg, true);
+	pfx = alc_get_line_out_pfx(spec, true);
 	if (!pfx)
 		pfx = "Front";
 	for (i = 0; i < 2; i++) {
@@ -12204,7 +12315,7 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
-static struct hda_verb alc262_volume_init_verbs[] = {
+static const struct hda_verb alc262_volume_init_verbs[] = {
 	/*
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 */
@@ -12265,7 +12376,7 @@ static struct hda_verb alc262_volume_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb alc262_HP_BPC_init_verbs[] = {
+static const struct hda_verb alc262_HP_BPC_init_verbs[] = {
 	/*
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 */
@@ -12369,7 +12480,7 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
+static const struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
 	/*
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 */
@@ -12465,7 +12576,7 @@ static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
+static const struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
 
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },	/* Front Speaker */
 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
@@ -12501,7 +12612,7 @@ static const struct alc_fixup alc262_fixups[] = {
 	},
 };
 
-static struct snd_pci_quirk alc262_fixup_tbl[] = {
+static const struct snd_pci_quirk alc262_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
 	{}
 };
@@ -12524,7 +12635,7 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 	int err;
-	static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
+	static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
 
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 					   alc262_ignore);
@@ -12609,7 +12720,7 @@ static const char * const alc262_models[ALC262_MODEL_LAST] = {
 	[ALC262_AUTO]		= "auto",
 };
 
-static struct snd_pci_quirk alc262_cfg_tbl[] = {
+static const struct snd_pci_quirk alc262_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
 	SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
 	SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
@@ -12661,7 +12772,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
 	{}
 };
 
-static struct alc_config_preset alc262_presets[] = {
+static const struct alc_config_preset alc262_presets[] = {
 	[ALC262_BASIC] = {
 		.mixers = { alc262_base_mixer },
 		.init_verbs = { alc262_init_verbs },
@@ -12682,9 +12793,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
-		.unsol_event = alc262_hippo_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc262_hippo_setup,
-		.init_hook = alc262_hippo_automute,
+		.init_hook = alc_inithook,
 	},
 	[ALC262_HIPPO_1] = {
 		.mixers = { alc262_hippo1_mixer },
@@ -12696,9 +12807,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
-		.unsol_event = alc262_hippo_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc262_hippo1_setup,
-		.init_hook = alc262_hippo_automute,
+		.init_hook = alc_inithook,
 	},
 	[ALC262_FUJITSU] = {
 		.mixers = { alc262_fujitsu_mixer },
@@ -12711,8 +12822,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_fujitsu_capture_source,
-		.unsol_event = alc262_fujitsu_unsol_event,
-		.init_hook = alc262_fujitsu_init_hook,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc262_fujitsu_setup,
+		.init_hook = alc_inithook,
 	},
 	[ALC262_HP_BPC] = {
 		.mixers = { alc262_HP_BPC_mixer },
@@ -12723,8 +12835,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_HP_capture_source,
-		.unsol_event = alc262_hp_bpc_unsol_event,
-		.init_hook = alc262_hp_bpc_automute,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc262_hp_bpc_setup,
+		.init_hook = alc_inithook,
 	},
 	[ALC262_HP_BPC_D7000_WF] = {
 		.mixers = { alc262_HP_BPC_WildWest_mixer },
@@ -12735,8 +12848,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_HP_D7000_capture_source,
-		.unsol_event = alc262_hp_wildwest_unsol_event,
-		.init_hook = alc262_hp_wildwest_automute,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc262_hp_wildwest_setup,
+		.init_hook = alc_inithook,
 	},
 	[ALC262_HP_BPC_D7000_WL] = {
 		.mixers = { alc262_HP_BPC_WildWest_mixer,
@@ -12748,8 +12862,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_HP_D7000_capture_source,
-		.unsol_event = alc262_hp_wildwest_unsol_event,
-		.init_hook = alc262_hp_wildwest_automute,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc262_hp_wildwest_setup,
+		.init_hook = alc_inithook,
 	},
 	[ALC262_HP_TC_T5735] = {
 		.mixers = { alc262_hp_t5735_mixer },
@@ -12792,9 +12907,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
-		.unsol_event = alc262_hippo_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc262_hippo_setup,
-		.init_hook = alc262_hippo_automute,
+		.init_hook = alc_inithook,
 	},
 	[ALC262_BENQ_T31] = {
 		.mixers = { alc262_benq_t31_mixer },
@@ -12806,9 +12921,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
-		.unsol_event = alc262_hippo_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc262_hippo_setup,
-		.init_hook = alc262_hippo_automute,
+		.init_hook = alc_inithook,
 	},
 	[ALC262_ULTRA] = {
 		.mixers = { alc262_ultra_mixer },
@@ -12837,7 +12952,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_fujitsu_capture_source,
-		.unsol_event = alc262_lenovo_3000_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc262_lenovo_3000_setup,
+		.init_hook = alc_inithook,
 	},
 	[ALC262_NEC] = {
 		.mixers = { alc262_nec_mixer },
@@ -12874,9 +12991,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
-		.unsol_event = alc262_hippo_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc262_hippo_setup,
-		.init_hook = alc262_hippo_automute,
+		.init_hook = alc_inithook,
 	},
 	[ALC262_TYAN] = {
 		.mixers = { alc262_tyan_mixer },
@@ -12888,9 +13005,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc262_tyan_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 };
 
@@ -13011,6 +13128,7 @@ static int patch_alc262(struct hda_codec *codec)
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC262_AUTO)
 		spec->init_hook = alc262_auto_init;
+	spec->shutup = alc_eapd_shutup;
 
 	alc_init_jacks(codec);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -13027,24 +13145,24 @@ static int patch_alc262(struct hda_codec *codec)
 #define ALC268_DIGOUT_NID	ALC880_DIGOUT_NID
 #define alc268_modes		alc260_modes
 
-static hda_nid_t alc268_dac_nids[2] = {
+static const hda_nid_t alc268_dac_nids[2] = {
 	/* front, hp */
 	0x02, 0x03
 };
 
-static hda_nid_t alc268_adc_nids[2] = {
+static const hda_nid_t alc268_adc_nids[2] = {
 	/* ADC0-1 */
 	0x08, 0x07
 };
 
-static hda_nid_t alc268_adc_nids_alt[1] = {
+static const hda_nid_t alc268_adc_nids_alt[1] = {
 	/* ADC0 */
 	0x08
 };
 
-static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
+static const hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
 
-static struct snd_kcontrol_new alc268_base_mixer[] = {
+static const struct snd_kcontrol_new alc268_base_mixer[] = {
 	/* output mixer control */
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -13056,7 +13174,7 @@ static struct snd_kcontrol_new alc268_base_mixer[] = {
 	{ }
 };
 
-static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
+static const struct snd_kcontrol_new alc268_toshiba_mixer[] = {
 	/* output mixer control */
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
@@ -13068,7 +13186,7 @@ static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
 };
 
 /* bind Beep switches of both NID 0x0f and 0x10 */
-static struct hda_bind_ctls alc268_bind_beep_sw = {
+static const struct hda_bind_ctls alc268_bind_beep_sw = {
 	.ops = &snd_hda_bind_sw,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
@@ -13077,27 +13195,27 @@ static struct hda_bind_ctls alc268_bind_beep_sw = {
 	},
 };
 
-static struct snd_kcontrol_new alc268_beep_mixer[] = {
+static const struct snd_kcontrol_new alc268_beep_mixer[] = {
 	HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
 	HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
 	{ }
 };
 
-static struct hda_verb alc268_eapd_verbs[] = {
+static const struct hda_verb alc268_eapd_verbs[] = {
 	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{ }
 };
 
 /* Toshiba specific */
-static struct hda_verb alc268_toshiba_verbs[] = {
+static const struct hda_verb alc268_toshiba_verbs[] = {
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
 	{ } /* end */
 };
 
 /* Acer specific */
 /* bind volumes of both NID 0x02 and 0x03 */
-static struct hda_bind_ctls alc268_acer_bind_master_vol = {
+static const struct hda_bind_ctls alc268_acer_bind_master_vol = {
 	.ops = &snd_hda_bind_vol,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
@@ -13106,66 +13224,44 @@ static struct hda_bind_ctls alc268_acer_bind_master_vol = {
 	},
 };
 
-/* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc268_acer_automute(struct hda_codec *codec, int force)
+static void alc268_acer_setup(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
-	unsigned int mute;
 
-	if (force || !spec->sense_updated) {
-		spec->jack_present = snd_hda_jack_detect(codec, 0x14);
-		spec->sense_updated = 1;
-	}
-	if (spec->jack_present)
-		mute = HDA_AMP_MUTE; /* mute internal speaker */
-	else /* unmute internal speaker if necessary */
-		mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, mute);
+	spec->autocfg.hp_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[0] = 0x15;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
+#define alc268_acer_master_sw_get	alc262_hp_master_sw_get
+#define alc268_acer_master_sw_put	alc262_hp_master_sw_put
 
-/* bind hp and internal speaker mute (with plug check) */
-static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
-				     struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	long *valp = ucontrol->value.integer.value;
-	int change;
-
-	change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
-	if (change)
-		alc268_acer_automute(codec, 0);
-	return change;
-}
-
-static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
+static const struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
 	/* output mixer control */
 	HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
-		.subdevice = HDA_SUBDEV_AMP_FLAG,
-		.info = snd_hda_mixer_amp_switch_info,
-		.get = snd_hda_mixer_amp_switch_get,
+		.subdevice = HDA_SUBDEV_NID_FLAG | 0x15,
+		.info = snd_ctl_boolean_mono_info,
+		.get = alc268_acer_master_sw_get,
 		.put = alc268_acer_master_sw_put,
-		.private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
 	},
 	HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
 	{ }
 };
 
-static struct snd_kcontrol_new alc268_acer_mixer[] = {
+static const struct snd_kcontrol_new alc268_acer_mixer[] = {
 	/* output mixer control */
 	HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
-		.subdevice = HDA_SUBDEV_AMP_FLAG,
-		.info = snd_hda_mixer_amp_switch_info,
-		.get = snd_hda_mixer_amp_switch_get,
+		.subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
+		.info = snd_ctl_boolean_mono_info,
+		.get = alc268_acer_master_sw_get,
 		.put = alc268_acer_master_sw_put,
-		.private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
 	},
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
@@ -13173,24 +13269,23 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = {
 	{ }
 };
 
-static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
+static const struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
 	/* output mixer control */
 	HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
-		.subdevice = HDA_SUBDEV_AMP_FLAG,
-		.info = snd_hda_mixer_amp_switch_info,
-		.get = snd_hda_mixer_amp_switch_get,
+		.subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
+		.info = snd_ctl_boolean_mono_info,
+		.get = alc268_acer_master_sw_get,
 		.put = alc268_acer_master_sw_put,
-		.private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
 	},
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
 	{ }
 };
 
-static struct hda_verb alc268_acer_aspire_one_verbs[] = {
+static const struct hda_verb alc268_acer_aspire_one_verbs[] = {
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
@@ -13200,7 +13295,7 @@ static struct hda_verb alc268_acer_aspire_one_verbs[] = {
 	{ }
 };
 
-static struct hda_verb alc268_acer_verbs[] = {
+static const struct hda_verb alc268_acer_verbs[] = {
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
 	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -13212,53 +13307,16 @@ static struct hda_verb alc268_acer_verbs[] = {
 };
 
 /* unsolicited event for HP jack sensing */
-#define alc268_toshiba_unsol_event	alc262_hippo_unsol_event
 #define alc268_toshiba_setup		alc262_hippo_setup
-#define alc268_toshiba_automute		alc262_hippo_automute
-
-static void alc268_acer_unsol_event(struct hda_codec *codec,
-				       unsigned int res)
-{
-	if ((res >> 26) != ALC880_HP_EVENT)
-		return;
-	alc268_acer_automute(codec, 1);
-}
-
-static void alc268_acer_init_hook(struct hda_codec *codec)
-{
-	alc268_acer_automute(codec, 1);
-}
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_jack_detect(codec, 0x15);
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
-				 HDA_AMP_MUTE, bits);
-}
-
-static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
-				    unsigned int res)
-{
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc268_aspire_one_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
-}
 
 static void alc268_acer_lc_setup(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute_mixer_nid[0] = 0x0f;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.mux_idx = 0;
 	spec->int_mic.pin = 0x12;
@@ -13266,13 +13324,7 @@ static void alc268_acer_lc_setup(struct hda_codec *codec)
 	spec->auto_mic = 1;
 }
 
-static void alc268_acer_lc_init_hook(struct hda_codec *codec)
-{
-	alc268_aspire_one_speaker_automute(codec);
-	alc_mic_automute(codec);
-}
-
-static struct snd_kcontrol_new alc268_dell_mixer[] = {
+static const struct snd_kcontrol_new alc268_dell_mixer[] = {
 	/* output mixer control */
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -13283,7 +13335,7 @@ static struct snd_kcontrol_new alc268_dell_mixer[] = {
 	{ }
 };
 
-static struct hda_verb alc268_dell_verbs[] = {
+static const struct hda_verb alc268_dell_verbs[] = {
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
@@ -13303,9 +13355,11 @@ static void alc268_dell_setup(struct hda_codec *codec)
 	spec->int_mic.pin = 0x19;
 	spec->int_mic.mux_idx = 1;
 	spec->auto_mic = 1;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
 }
 
-static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
+static const struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
@@ -13317,7 +13371,7 @@ static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
 	{ }
 };
 
-static struct hda_verb alc267_quanta_il1_verbs[] = {
+static const struct hda_verb alc267_quanta_il1_verbs[] = {
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
 	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
 	{ }
@@ -13333,12 +13387,14 @@ static void alc267_quanta_il1_setup(struct hda_codec *codec)
 	spec->int_mic.pin = 0x19;
 	spec->int_mic.mux_idx = 1;
 	spec->auto_mic = 1;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
 }
 
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
-static struct hda_verb alc268_base_init_verbs[] = {
+static const struct hda_verb alc268_base_init_verbs[] = {
 	/* Unmute DAC0-1 and set vol = 0 */
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
@@ -13386,7 +13442,7 @@ static struct hda_verb alc268_base_init_verbs[] = {
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
-static struct hda_verb alc268_volume_init_verbs[] = {
+static const struct hda_verb alc268_volume_init_verbs[] = {
 	/* set output DAC */
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
@@ -13412,20 +13468,20 @@ static struct hda_verb alc268_volume_init_verbs[] = {
 	{ }
 };
 
-static struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
+static const struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
+static const struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
 	_DEFINE_CAPSRC(1),
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc268_capture_mixer[] = {
+static const struct snd_kcontrol_new alc268_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
@@ -13434,7 +13490,7 @@ static struct snd_kcontrol_new alc268_capture_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_input_mux alc268_capture_source = {
+static const struct hda_input_mux alc268_capture_source = {
 	.num_items = 4,
 	.items = {
 		{ "Mic", 0x0 },
@@ -13444,7 +13500,7 @@ static struct hda_input_mux alc268_capture_source = {
 	},
 };
 
-static struct hda_input_mux alc268_acer_capture_source = {
+static const struct hda_input_mux alc268_acer_capture_source = {
 	.num_items = 3,
 	.items = {
 		{ "Mic", 0x0 },
@@ -13453,7 +13509,7 @@ static struct hda_input_mux alc268_acer_capture_source = {
 	},
 };
 
-static struct hda_input_mux alc268_acer_dmic_capture_source = {
+static const struct hda_input_mux alc268_acer_dmic_capture_source = {
 	.num_items = 3,
 	.items = {
 		{ "Mic", 0x0 },
@@ -13463,7 +13519,7 @@ static struct hda_input_mux alc268_acer_dmic_capture_source = {
 };
 
 #ifdef CONFIG_SND_DEBUG
-static struct snd_kcontrol_new alc268_test_mixer[] = {
+static const struct snd_kcontrol_new alc268_test_mixer[] = {
 	/* Volume widgets */
 	HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
@@ -13542,7 +13598,7 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
 						      HDA_OUTPUT));
 		if (err < 0)
 			return err;
-		spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
+		spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
 	}
 
 	if (nid != 0x16)
@@ -13715,7 +13771,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 	int err;
-	static hda_nid_t alc268_ignore[] = { 0 };
+	static const hda_nid_t alc268_ignore[] = { 0 };
 
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 					   alc268_ignore);
@@ -13795,7 +13851,7 @@ static const char * const alc268_models[ALC268_MODEL_LAST] = {
 	[ALC268_AUTO]		= "auto",
 };
 
-static struct snd_pci_quirk alc268_cfg_tbl[] = {
+static const struct snd_pci_quirk alc268_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
 	SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
 	SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
@@ -13820,7 +13876,7 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = {
 };
 
 /* Toshiba laptops have no unique PCI SSID but only codec SSID */
-static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
+static const struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
 	SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
 	SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
@@ -13828,7 +13884,7 @@ static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
 	{}
 };
 
-static struct alc_config_preset alc268_presets[] = {
+static const struct alc_config_preset alc268_presets[] = {
 	[ALC267_QUANTA_IL1] = {
 		.mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
 			    alc268_capture_nosrc_mixer },
@@ -13874,9 +13930,9 @@ static struct alc_config_preset alc268_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
 		.channel_mode = alc268_modes,
 		.input_mux = &alc268_capture_source,
-		.unsol_event = alc268_toshiba_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc268_toshiba_setup,
-		.init_hook = alc268_toshiba_automute,
+		.init_hook = alc_inithook,
 	},
 	[ALC268_ACER] = {
 		.mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
@@ -13892,8 +13948,9 @@ static struct alc_config_preset alc268_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
 		.channel_mode = alc268_modes,
 		.input_mux = &alc268_acer_capture_source,
-		.unsol_event = alc268_acer_unsol_event,
-		.init_hook = alc268_acer_init_hook,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc268_acer_setup,
+		.init_hook = alc_inithook,
 	},
 	[ALC268_ACER_DMIC] = {
 		.mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
@@ -13909,8 +13966,9 @@ static struct alc_config_preset alc268_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
 		.channel_mode = alc268_modes,
 		.input_mux = &alc268_acer_dmic_capture_source,
-		.unsol_event = alc268_acer_unsol_event,
-		.init_hook = alc268_acer_init_hook,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc268_acer_setup,
+		.init_hook = alc_inithook,
 	},
 	[ALC268_ACER_ASPIRE_ONE] = {
 		.mixers = { alc268_acer_aspire_one_mixer,
@@ -13926,9 +13984,9 @@ static struct alc_config_preset alc268_presets[] = {
 		.hp_nid = 0x03,
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
 		.channel_mode = alc268_modes,
-		.unsol_event = alc268_acer_lc_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc268_acer_lc_setup,
-		.init_hook = alc268_acer_lc_init_hook,
+		.init_hook = alc_inithook,
 	},
 	[ALC268_DELL] = {
 		.mixers = { alc268_dell_mixer, alc268_beep_mixer,
@@ -13962,8 +14020,9 @@ static struct alc_config_preset alc268_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
 		.channel_mode = alc268_modes,
 		.input_mux = &alc268_capture_source,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc268_toshiba_setup,
-		.init_hook = alc268_toshiba_automute,
+		.init_hook = alc_inithook,
 	},
 #ifdef CONFIG_SND_DEBUG
 	[ALC268_TEST] = {
@@ -14085,6 +14144,7 @@ static int patch_alc268(struct hda_codec *codec)
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC268_AUTO)
 		spec->init_hook = alc268_auto_init;
+	spec->shutup = alc_eapd_shutup;
 
 	alc_init_jacks(codec);
 
@@ -14098,32 +14158,32 @@ static int patch_alc268(struct hda_codec *codec)
 
 #define alc269_dac_nids		alc260_dac_nids
 
-static hda_nid_t alc269_adc_nids[1] = {
+static const hda_nid_t alc269_adc_nids[1] = {
 	/* ADC1 */
 	0x08,
 };
 
-static hda_nid_t alc269_capsrc_nids[1] = {
+static const hda_nid_t alc269_capsrc_nids[1] = {
 	0x23,
 };
 
-static hda_nid_t alc269vb_adc_nids[1] = {
+static const hda_nid_t alc269vb_adc_nids[1] = {
 	/* ADC1 */
 	0x09,
 };
 
-static hda_nid_t alc269vb_capsrc_nids[1] = {
+static const hda_nid_t alc269vb_capsrc_nids[1] = {
 	0x22,
 };
 
-static hda_nid_t alc269_adc_candidates[] = {
+static const hda_nid_t alc269_adc_candidates[] = {
 	0x08, 0x09, 0x07, 0x11,
 };
 
 #define alc269_modes		alc260_modes
 #define alc269_capture_source	alc880_lg_lw_capture_source
 
-static struct snd_kcontrol_new alc269_base_mixer[] = {
+static const struct snd_kcontrol_new alc269_base_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
@@ -14139,7 +14199,7 @@ static struct snd_kcontrol_new alc269_base_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
+static const struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
 	/* output mixer control */
 	HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
 	{
@@ -14160,7 +14220,7 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
 	{ }
 };
 
-static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
+static const struct snd_kcontrol_new alc269_lifebook_mixer[] = {
 	/* output mixer control */
 	HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
 	{
@@ -14184,7 +14244,7 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
 	{ }
 };
 
-static struct snd_kcontrol_new alc269_laptop_mixer[] = {
+static const struct snd_kcontrol_new alc269_laptop_mixer[] = {
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -14192,7 +14252,7 @@ static struct snd_kcontrol_new alc269_laptop_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
+static const struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
@@ -14200,14 +14260,14 @@ static struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc269_asus_mixer[] = {
+static const struct snd_kcontrol_new alc269_asus_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT),
 	{ } /* end */
 };
 
 /* capture mixer elements */
-static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
+static const struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
@@ -14215,14 +14275,14 @@ static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
+static const struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
+static const struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
@@ -14230,7 +14290,7 @@ static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
+static const struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
@@ -14240,7 +14300,7 @@ static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
 /* FSC amilo */
 #define alc269_fujitsu_mixer	alc269_laptop_mixer
 
-static struct hda_verb alc269_quanta_fl1_verbs[] = {
+static const struct hda_verb alc269_quanta_fl1_verbs[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -14250,7 +14310,7 @@ static struct hda_verb alc269_quanta_fl1_verbs[] = {
 	{ }
 };
 
-static struct hda_verb alc269_lifebook_verbs[] = {
+static const struct hda_verb alc269_lifebook_verbs[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
@@ -14267,15 +14327,7 @@ static struct hda_verb alc269_lifebook_verbs[] = {
 /* toggle speaker-output according to the hp-jack state */
 static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
 {
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_jack_detect(codec, 0x15);
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
-				 HDA_AMP_MUTE, bits);
+	alc_hp_automute(codec);
 
 	snd_hda_codec_write(codec, 0x20, 0,
 			AC_VERB_SET_COEF_INDEX, 0x0c);
@@ -14288,34 +14340,8 @@ static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
 			AC_VERB_SET_PROC_COEF, 0x480);
 }
 
-/* toggle speaker-output according to the hp-jacks state */
-static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-	unsigned char bits;
-
-	/* Check laptop headphone socket */
-	present = snd_hda_jack_detect(codec, 0x15);
-
-	/* Check port replicator headphone socket */
-	present |= snd_hda_jack_detect(codec, 0x1a);
-
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
-				 HDA_AMP_MUTE, bits);
-
-	snd_hda_codec_write(codec, 0x20, 0,
-			AC_VERB_SET_COEF_INDEX, 0x0c);
-	snd_hda_codec_write(codec, 0x20, 0,
-			AC_VERB_SET_PROC_COEF, 0x680);
-
-	snd_hda_codec_write(codec, 0x20, 0,
-			AC_VERB_SET_COEF_INDEX, 0x0c);
-	snd_hda_codec_write(codec, 0x20, 0,
-			AC_VERB_SET_PROC_COEF, 0x480);
-}
+#define alc269_lifebook_speaker_automute \
+	alc269_quanta_fl1_speaker_automute
 
 static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
 {
@@ -14364,6 +14390,9 @@ static void alc269_quanta_fl1_setup(struct hda_codec *codec)
 	struct alc_spec *spec = codec->spec;
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.mux_idx = 0;
 	spec->int_mic.pin = 0x19;
@@ -14377,13 +14406,24 @@ static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
 	alc_mic_automute(codec);
 }
 
+static void alc269_lifebook_setup(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.hp_pins[1] = 0x1a;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
+}
+
 static void alc269_lifebook_init_hook(struct hda_codec *codec)
 {
 	alc269_lifebook_speaker_automute(codec);
 	alc269_lifebook_mic_autoswitch(codec);
 }
 
-static struct hda_verb alc269_laptop_dmic_init_verbs[] = {
+static const struct hda_verb alc269_laptop_dmic_init_verbs[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
@@ -14394,7 +14434,7 @@ static struct hda_verb alc269_laptop_dmic_init_verbs[] = {
 	{}
 };
 
-static struct hda_verb alc269_laptop_amic_init_verbs[] = {
+static const struct hda_verb alc269_laptop_amic_init_verbs[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
@@ -14404,7 +14444,7 @@ static struct hda_verb alc269_laptop_amic_init_verbs[] = {
 	{}
 };
 
-static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
+static const struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
 	{0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
@@ -14415,7 +14455,7 @@ static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
 	{}
 };
 
-static struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
+static const struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
 	{0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
@@ -14426,7 +14466,7 @@ static struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
 	{}
 };
 
-static struct hda_verb alc271_acer_dmic_verbs[] = {
+static const struct hda_verb alc271_acer_dmic_verbs[] = {
 	{0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
 	{0x20, AC_VERB_SET_PROC_COEF, 0x4000},
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
@@ -14440,42 +14480,14 @@ static struct hda_verb alc271_acer_dmic_verbs[] = {
 	{ }
 };
 
-/* toggle speaker-output according to the hp-jack state */
-static void alc269_speaker_automute(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-	unsigned int nid = spec->autocfg.hp_pins[0];
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_jack_detect(codec, nid);
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_input_jack_report(codec, nid);
-}
-
-/* unsolicited event for HP jack sensing */
-static void alc269_laptop_unsol_event(struct hda_codec *codec,
-				     unsigned int res)
-{
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc269_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
-}
-
 static void alc269_laptop_amic_setup(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.mux_idx = 0;
 	spec->int_mic.pin = 0x19;
@@ -14488,6 +14500,9 @@ static void alc269_laptop_dmic_setup(struct hda_codec *codec)
 	struct alc_spec *spec = codec->spec;
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.mux_idx = 0;
 	spec->int_mic.pin = 0x12;
@@ -14500,6 +14515,9 @@ static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
 	struct alc_spec *spec = codec->spec;
 	spec->autocfg.hp_pins[0] = 0x21;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.mux_idx = 0;
 	spec->int_mic.pin = 0x19;
@@ -14512,6 +14530,9 @@ static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
 	struct alc_spec *spec = codec->spec;
 	spec->autocfg.hp_pins[0] = 0x21;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.mux_idx = 0;
 	spec->int_mic.pin = 0x12;
@@ -14519,16 +14540,10 @@ static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
 	spec->auto_mic = 1;
 }
 
-static void alc269_laptop_inithook(struct hda_codec *codec)
-{
-	alc269_speaker_automute(codec);
-	alc_mic_automute(codec);
-}
-
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
-static struct hda_verb alc269_init_verbs[] = {
+static const struct hda_verb alc269_init_verbs[] = {
 	/*
 	 * Unmute ADC0 and set the default input to mic-in
 	 */
@@ -14571,7 +14586,7 @@ static struct hda_verb alc269_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb alc269vb_init_verbs[] = {
+static const struct hda_verb alc269vb_init_verbs[] = {
 	/*
 	 * Unmute ADC0 and set the default input to mic-in
 	 */
@@ -14629,7 +14644,7 @@ static struct hda_verb alc269vb_init_verbs[] = {
 #define alc269_pcm_digital_playback	alc880_pcm_digital_playback
 #define alc269_pcm_digital_capture	alc880_pcm_digital_capture
 
-static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
+static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 8,
@@ -14642,7 +14657,7 @@ static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
 	},
 };
 
-static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
+static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -14726,7 +14741,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 	int err;
-	static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
+	static const hda_nid_t alc269_ignore[] = { 0x1d, 0 };
 
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 					   alc269_ignore);
@@ -14796,7 +14811,6 @@ static void alc269_auto_init(struct hda_codec *codec)
 		alc_inithook(codec);
 }
 
-#ifdef SND_HDA_NEEDS_RESUME
 static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
 {
 	int val = alc_read_coef_idx(codec, 0x04);
@@ -14807,25 +14821,17 @@ static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
 	alc_write_coef_idx(codec, 0x04, val);
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static int alc269_suspend(struct hda_codec *codec, pm_message_t state)
+static void alc269_shutup(struct hda_codec *codec)
 {
-	struct alc_spec *spec = codec->spec;
-
 	if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
 		alc269_toggle_power_output(codec, 0);
 	if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
 		alc269_toggle_power_output(codec, 0);
 		msleep(150);
 	}
-
-	alc_shutup(codec);
-	if (spec && spec->power_hook)
-		spec->power_hook(codec);
-	return 0;
 }
-#endif /* CONFIG_SND_HDA_POWER_SAVE */
 
+#ifdef SND_HDA_NEEDS_RESUME
 static int alc269_resume(struct hda_codec *codec)
 {
 	if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
@@ -14864,7 +14870,7 @@ static void alc269_fixup_hweq(struct hda_codec *codec,
 static void alc271_fixup_dmic(struct hda_codec *codec,
 			      const struct alc_fixup *fix, int action)
 {
-	static struct hda_verb verbs[] = {
+	static const struct hda_verb verbs[] = {
 		{0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
 		{0x20, AC_VERB_SET_PROC_COEF, 0x4000},
 		{}
@@ -14947,7 +14953,7 @@ static const struct alc_fixup alc269_fixups[] = {
 	},
 };
 
-static struct snd_pci_quirk alc269_fixup_tbl[] = {
+static const struct snd_pci_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
 	SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
 	SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
@@ -14978,7 +14984,7 @@ static const char * const alc269_models[ALC269_MODEL_LAST] = {
 	[ALC269_AUTO]			= "auto",
 };
 
-static struct snd_pci_quirk alc269_cfg_tbl[] = {
+static const struct snd_pci_quirk alc269_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
 	SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER),
 	SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
@@ -15036,7 +15042,7 @@ static struct snd_pci_quirk alc269_cfg_tbl[] = {
 	{}
 };
 
-static struct alc_config_preset alc269_presets[] = {
+static const struct alc_config_preset alc269_presets[] = {
 	[ALC269_BASIC] = {
 		.mixers = { alc269_base_mixer },
 		.init_verbs = { alc269_init_verbs },
@@ -15070,9 +15076,9 @@ static struct alc_config_preset alc269_presets[] = {
 		.hp_nid = 0x03,
 		.num_channel_mode = ARRAY_SIZE(alc269_modes),
 		.channel_mode = alc269_modes,
-		.unsol_event = alc269_laptop_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc269_laptop_amic_setup,
-		.init_hook = alc269_laptop_inithook,
+		.init_hook = alc_inithook,
 	},
 	[ALC269_DMIC] = {
 		.mixers = { alc269_laptop_mixer },
@@ -15084,9 +15090,9 @@ static struct alc_config_preset alc269_presets[] = {
 		.hp_nid = 0x03,
 		.num_channel_mode = ARRAY_SIZE(alc269_modes),
 		.channel_mode = alc269_modes,
-		.unsol_event = alc269_laptop_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc269_laptop_dmic_setup,
-		.init_hook = alc269_laptop_inithook,
+		.init_hook = alc_inithook,
 	},
 	[ALC269VB_AMIC] = {
 		.mixers = { alc269vb_laptop_mixer },
@@ -15098,9 +15104,9 @@ static struct alc_config_preset alc269_presets[] = {
 		.hp_nid = 0x03,
 		.num_channel_mode = ARRAY_SIZE(alc269_modes),
 		.channel_mode = alc269_modes,
-		.unsol_event = alc269_laptop_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc269vb_laptop_amic_setup,
-		.init_hook = alc269_laptop_inithook,
+		.init_hook = alc_inithook,
 	},
 	[ALC269VB_DMIC] = {
 		.mixers = { alc269vb_laptop_mixer },
@@ -15112,9 +15118,9 @@ static struct alc_config_preset alc269_presets[] = {
 		.hp_nid = 0x03,
 		.num_channel_mode = ARRAY_SIZE(alc269_modes),
 		.channel_mode = alc269_modes,
-		.unsol_event = alc269_laptop_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc269vb_laptop_dmic_setup,
-		.init_hook = alc269_laptop_inithook,
+		.init_hook = alc_inithook,
 	},
 	[ALC269_FUJITSU] = {
 		.mixers = { alc269_fujitsu_mixer },
@@ -15126,9 +15132,9 @@ static struct alc_config_preset alc269_presets[] = {
 		.hp_nid = 0x03,
 		.num_channel_mode = ARRAY_SIZE(alc269_modes),
 		.channel_mode = alc269_modes,
-		.unsol_event = alc269_laptop_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc269_laptop_dmic_setup,
-		.init_hook = alc269_laptop_inithook,
+		.init_hook = alc_inithook,
 	},
 	[ALC269_LIFEBOOK] = {
 		.mixers = { alc269_lifebook_mixer },
@@ -15140,6 +15146,7 @@ static struct alc_config_preset alc269_presets[] = {
 		.channel_mode = alc269_modes,
 		.input_mux = &alc269_capture_source,
 		.unsol_event = alc269_lifebook_unsol_event,
+		.setup = alc269_lifebook_setup,
 		.init_hook = alc269_lifebook_init_hook,
 	},
 	[ALC271_ACER] = {
@@ -15185,14 +15192,21 @@ static int alc269_fill_coef(struct hda_codec *codec)
 		val = alc_read_coef_idx(codec, 0xd);
 		if ((val & 0x0c00) >> 10 != 0x1) {
 			/* Capless ramp up clock control */
-			alc_write_coef_idx(codec, 0xd, val | 1<<10);
+			alc_write_coef_idx(codec, 0xd, val | (1<<10));
 		}
 		val = alc_read_coef_idx(codec, 0x17);
 		if ((val & 0x01c0) >> 6 != 0x4) {
 			/* Class D power on reset */
-			alc_write_coef_idx(codec, 0x17, val | 1<<7);
+			alc_write_coef_idx(codec, 0x17, val | (1<<7));
 		}
 	}
+
+	val = alc_read_coef_idx(codec, 0xd); /* Class D */
+	alc_write_coef_idx(codec, 0xd, val | (1<<14));
+
+	val = alc_read_coef_idx(codec, 0x4); /* HP */
+	alc_write_coef_idx(codec, 0x4, val | (1<<11));
+
 	return 0;
 }
 
@@ -15313,14 +15327,12 @@ static int patch_alc269(struct hda_codec *codec)
 	spec->vmaster_nid = 0x02;
 
 	codec->patch_ops = alc_patch_ops;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-	codec->patch_ops.suspend = alc269_suspend;
-#endif
 #ifdef SND_HDA_NEEDS_RESUME
 	codec->patch_ops.resume = alc269_resume;
 #endif
 	if (board_config == ALC269_AUTO)
 		spec->init_hook = alc269_auto_init;
+	spec->shutup = alc269_shutup;
 
 	alc_init_jacks(codec);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -15341,7 +15353,7 @@ static int patch_alc269(struct hda_codec *codec)
  * set the path ways for 2 channel output
  * need to set the codec line out and mic 1 pin widgets to inputs
  */
-static struct hda_verb alc861_threestack_ch2_init[] = {
+static const struct hda_verb alc861_threestack_ch2_init[] = {
 	/* set pin widget 1Ah (line in) for input */
 	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
 	/* set pin widget 18h (mic1/2) for input, for mic also enable
@@ -15360,7 +15372,7 @@ static struct hda_verb alc861_threestack_ch2_init[] = {
  * 6ch mode
  * need to set the codec line out and mic 1 pin widgets to outputs
  */
-static struct hda_verb alc861_threestack_ch6_init[] = {
+static const struct hda_verb alc861_threestack_ch6_init[] = {
 	/* set pin widget 1Ah (line in) for output (Back Surround)*/
 	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
 	/* set pin widget 18h (mic1) for output (CLFE)*/
@@ -15377,30 +15389,30 @@ static struct hda_verb alc861_threestack_ch6_init[] = {
 	{ } /* end */
 };
 
-static struct hda_channel_mode alc861_threestack_modes[2] = {
+static const struct hda_channel_mode alc861_threestack_modes[2] = {
 	{ 2, alc861_threestack_ch2_init },
 	{ 6, alc861_threestack_ch6_init },
 };
 /* Set mic1 as input and unmute the mixer */
-static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
+static const struct hda_verb alc861_uniwill_m31_ch2_init[] = {
 	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
 	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
 	{ } /* end */
 };
 /* Set mic1 as output and mute mixer */
-static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
+static const struct hda_verb alc861_uniwill_m31_ch4_init[] = {
 	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
 	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
 	{ } /* end */
 };
 
-static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
+static const struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
 	{ 2, alc861_uniwill_m31_ch2_init },
 	{ 4, alc861_uniwill_m31_ch4_init },
 };
 
 /* Set mic1 and line-in as input and unmute the mixer */
-static struct hda_verb alc861_asus_ch2_init[] = {
+static const struct hda_verb alc861_asus_ch2_init[] = {
 	/* set pin widget 1Ah (line in) for input */
 	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
 	/* set pin widget 18h (mic1/2) for input, for mic also enable
@@ -15416,7 +15428,7 @@ static struct hda_verb alc861_asus_ch2_init[] = {
 	{ } /* end */
 };
 /* Set mic1 nad line-in as output and mute mixer */
-static struct hda_verb alc861_asus_ch6_init[] = {
+static const struct hda_verb alc861_asus_ch6_init[] = {
 	/* set pin widget 1Ah (line in) for output (Back Surround)*/
 	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
 	/* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
@@ -15434,14 +15446,14 @@ static struct hda_verb alc861_asus_ch6_init[] = {
 	{ } /* end */
 };
 
-static struct hda_channel_mode alc861_asus_modes[2] = {
+static const struct hda_channel_mode alc861_asus_modes[2] = {
 	{ 2, alc861_asus_ch2_init },
 	{ 6, alc861_asus_ch6_init },
 };
 
 /* patch-ALC861 */
 
-static struct snd_kcontrol_new alc861_base_mixer[] = {
+static const struct snd_kcontrol_new alc861_base_mixer[] = {
         /* output mixer control */
 	HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
@@ -15464,7 +15476,7 @@ static struct snd_kcontrol_new alc861_base_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc861_3ST_mixer[] = {
+static const struct snd_kcontrol_new alc861_3ST_mixer[] = {
         /* output mixer control */
 	HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
@@ -15495,7 +15507,7 @@ static struct snd_kcontrol_new alc861_3ST_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
+static const struct snd_kcontrol_new alc861_toshiba_mixer[] = {
         /* output mixer control */
 	HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
@@ -15504,7 +15516,7 @@ static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
+static const struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
         /* output mixer control */
 	HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
@@ -15535,7 +15547,7 @@ static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc861_asus_mixer[] = {
+static const struct snd_kcontrol_new alc861_asus_mixer[] = {
         /* output mixer control */
 	HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
@@ -15567,7 +15579,7 @@ static struct snd_kcontrol_new alc861_asus_mixer[] = {
 };
 
 /* additional mixer */
-static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
+static const struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
 	{ }
@@ -15576,7 +15588,7 @@ static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
-static struct hda_verb alc861_base_init_verbs[] = {
+static const struct hda_verb alc861_base_init_verbs[] = {
 	/*
 	 * Unmute ADC0 and set the default input to mic-in
 	 */
@@ -15642,7 +15654,7 @@ static struct hda_verb alc861_base_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb alc861_threestack_init_verbs[] = {
+static const struct hda_verb alc861_threestack_init_verbs[] = {
 	/*
 	 * Unmute ADC0 and set the default input to mic-in
 	 */
@@ -15703,7 +15715,7 @@ static struct hda_verb alc861_threestack_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
+static const struct hda_verb alc861_uniwill_m31_init_verbs[] = {
 	/*
 	 * Unmute ADC0 and set the default input to mic-in
 	 */
@@ -15765,7 +15777,7 @@ static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb alc861_asus_init_verbs[] = {
+static const struct hda_verb alc861_asus_init_verbs[] = {
 	/*
 	 * Unmute ADC0 and set the default input to mic-in
 	 */
@@ -15831,7 +15843,7 @@ static struct hda_verb alc861_asus_init_verbs[] = {
 };
 
 /* additional init verbs for ASUS laptops */
-static struct hda_verb alc861_asus_laptop_init_verbs[] = {
+static const struct hda_verb alc861_asus_laptop_init_verbs[] = {
 	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
 	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
 	{ }
@@ -15840,7 +15852,7 @@ static struct hda_verb alc861_asus_laptop_init_verbs[] = {
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
-static struct hda_verb alc861_auto_init_verbs[] = {
+static const struct hda_verb alc861_auto_init_verbs[] = {
 	/*
 	 * Unmute ADC0 and set the default input to mic-in
 	 */
@@ -15889,7 +15901,7 @@ static struct hda_verb alc861_auto_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb alc861_toshiba_init_verbs[] = {
+static const struct hda_verb alc861_toshiba_init_verbs[] = {
 	{0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 
 	{ }
@@ -15922,26 +15934,26 @@ static void alc861_toshiba_unsol_event(struct hda_codec *codec,
 
 #define ALC861_DIGOUT_NID	0x07
 
-static struct hda_channel_mode alc861_8ch_modes[1] = {
+static const struct hda_channel_mode alc861_8ch_modes[1] = {
 	{ 8, NULL }
 };
 
-static hda_nid_t alc861_dac_nids[4] = {
+static const hda_nid_t alc861_dac_nids[4] = {
 	/* front, surround, clfe, side */
 	0x03, 0x06, 0x05, 0x04
 };
 
-static hda_nid_t alc660_dac_nids[3] = {
+static const hda_nid_t alc660_dac_nids[3] = {
 	/* front, clfe, surround */
 	0x03, 0x05, 0x06
 };
 
-static hda_nid_t alc861_adc_nids[1] = {
+static const hda_nid_t alc861_adc_nids[1] = {
 	/* ADC0-2 */
 	0x08,
 };
 
-static struct hda_input_mux alc861_capture_source = {
+static const struct hda_input_mux alc861_capture_source = {
 	.num_items = 5,
 	.items = {
 		{ "Mic", 0x0 },
@@ -15991,7 +16003,7 @@ static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
 		dac = alc861_look_for_dac(codec, nid);
 		if (!dac)
 			continue;
-		spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
+		spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
 	}
 	return 0;
 }
@@ -16014,11 +16026,15 @@ static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
 	static const char * const chname[4] = {
 		"Front", "Surround", NULL /*CLFE*/, "Side"
 	};
-	const char *pfx = alc_get_line_out_pfx(cfg, true);
+	const char *pfx = alc_get_line_out_pfx(spec, true);
 	hda_nid_t nid;
-	int i, err;
+	int i, err, noutputs;
 
-	for (i = 0; i < cfg->line_outs; i++) {
+	noutputs = cfg->line_outs;
+	if (spec->multi_ios > 0)
+		noutputs += spec->multi_ios;
+
+	for (i = 0; i < noutputs; i++) {
 		nid = spec->multiout.dac_nids[i];
 		if (!nid)
 			continue;
@@ -16151,7 +16167,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 	int err;
-	static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
+	static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
 
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 					   alc861_ignore);
@@ -16163,6 +16179,9 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
 	err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
 	if (err < 0)
 		return err;
+	err = alc_auto_add_multi_channel_mode(codec);
+	if (err < 0)
+		return err;
 	err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
 	if (err < 0)
 		return err;
@@ -16207,7 +16226,7 @@ static void alc861_auto_init(struct hda_codec *codec)
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list alc861_loopbacks[] = {
+static const struct hda_amp_list alc861_loopbacks[] = {
 	{ 0x15, HDA_INPUT, 0 },
 	{ 0x15, HDA_INPUT, 1 },
 	{ 0x15, HDA_INPUT, 2 },
@@ -16232,7 +16251,7 @@ static const char * const alc861_models[ALC861_MODEL_LAST] = {
 	[ALC861_AUTO]		= "auto",
 };
 
-static struct snd_pci_quirk alc861_cfg_tbl[] = {
+static const struct snd_pci_quirk alc861_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
 	SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
 	SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
@@ -16256,7 +16275,7 @@ static struct snd_pci_quirk alc861_cfg_tbl[] = {
 	{}
 };
 
-static struct alc_config_preset alc861_presets[] = {
+static const struct alc_config_preset alc861_presets[] = {
 	[ALC861_3ST] = {
 		.mixers = { alc861_3ST_mixer },
 		.init_verbs = { alc861_threestack_init_verbs },
@@ -16379,7 +16398,7 @@ static const struct alc_fixup alc861_fixups[] = {
 	},
 };
 
-static struct snd_pci_quirk alc861_fixup_tbl[] = {
+static const struct snd_pci_quirk alc861_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
 	{}
 };
@@ -16472,7 +16491,7 @@ static int patch_alc861(struct hda_codec *codec)
  */
 #define ALC861VD_DIGOUT_NID	0x06
 
-static hda_nid_t alc861vd_dac_nids[4] = {
+static const hda_nid_t alc861vd_dac_nids[4] = {
 	/* front, surr, clfe, side surr */
 	0x02, 0x03, 0x04, 0x05
 };
@@ -16484,21 +16503,21 @@ static hda_nid_t alc861vd_dac_nids[4] = {
  * - and it is the same as in 861vd.
  * adc_nids in ALC660vd are (is) the same as in 861vd
  */
-static hda_nid_t alc660vd_dac_nids[3] = {
+static const hda_nid_t alc660vd_dac_nids[3] = {
 	/* front, rear, clfe, rear_surr */
 	0x02, 0x04, 0x03
 };
 
-static hda_nid_t alc861vd_adc_nids[1] = {
+static const hda_nid_t alc861vd_adc_nids[1] = {
 	/* ADC0 */
 	0x09,
 };
 
-static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
+static const hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
 
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
-static struct hda_input_mux alc861vd_capture_source = {
+static const struct hda_input_mux alc861vd_capture_source = {
 	.num_items = 4,
 	.items = {
 		{ "Mic", 0x0 },
@@ -16508,7 +16527,7 @@ static struct hda_input_mux alc861vd_capture_source = {
 	},
 };
 
-static struct hda_input_mux alc861vd_dallas_capture_source = {
+static const struct hda_input_mux alc861vd_dallas_capture_source = {
 	.num_items = 2,
 	.items = {
 		{ "Mic", 0x0 },
@@ -16516,7 +16535,7 @@ static struct hda_input_mux alc861vd_dallas_capture_source = {
 	},
 };
 
-static struct hda_input_mux alc861vd_hp_capture_source = {
+static const struct hda_input_mux alc861vd_hp_capture_source = {
 	.num_items = 2,
 	.items = {
 		{ "Front Mic", 0x0 },
@@ -16527,14 +16546,14 @@ static struct hda_input_mux alc861vd_hp_capture_source = {
 /*
  * 2ch mode
  */
-static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
+static const struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
 	{ 2, NULL }
 };
 
 /*
  * 6ch mode
  */
-static struct hda_verb alc861vd_6stack_ch6_init[] = {
+static const struct hda_verb alc861vd_6stack_ch6_init[] = {
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -16545,7 +16564,7 @@ static struct hda_verb alc861vd_6stack_ch6_init[] = {
 /*
  * 8ch mode
  */
-static struct hda_verb alc861vd_6stack_ch8_init[] = {
+static const struct hda_verb alc861vd_6stack_ch8_init[] = {
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -16553,12 +16572,12 @@ static struct hda_verb alc861vd_6stack_ch8_init[] = {
 	{ } /* end */
 };
 
-static struct hda_channel_mode alc861vd_6stack_modes[2] = {
+static const struct hda_channel_mode alc861vd_6stack_modes[2] = {
 	{ 6, alc861vd_6stack_ch6_init },
 	{ 8, alc861vd_6stack_ch8_init },
 };
 
-static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
+static const struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Channel Mode",
@@ -16572,7 +16591,7 @@ static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
 /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
  *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
  */
-static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
+static const struct snd_kcontrol_new alc861vd_6st_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 
@@ -16608,7 +16627,7 @@ static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
+static const struct snd_kcontrol_new alc861vd_3st_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 
@@ -16631,7 +16650,7 @@ static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
+static const struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	/*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
 	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -16655,7 +16674,7 @@ static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
 /* Pin assignment: Speaker=0x14, HP = 0x15,
  *                 Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
  */
-static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
+static const struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
@@ -16672,7 +16691,7 @@ static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
 /* Pin assignment: Speaker=0x14, Line-out = 0x15,
  *                 Front Mic=0x18, ATAPI Mic = 0x19,
  */
-static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
+static const struct snd_kcontrol_new alc861vd_hp_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
@@ -16688,7 +16707,7 @@ static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
-static struct hda_verb alc861vd_volume_init_verbs[] = {
+static const struct hda_verb alc861vd_volume_init_verbs[] = {
 	/*
 	 * Unmute ADC0 and set the default input to mic-in
 	 */
@@ -16738,7 +16757,7 @@ static struct hda_verb alc861vd_volume_init_verbs[] = {
  * 3-stack pin configuration:
  * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
  */
-static struct hda_verb alc861vd_3stack_init_verbs[] = {
+static const struct hda_verb alc861vd_3stack_init_verbs[] = {
 	/*
 	 * Set pin mode and muting
 	 */
@@ -16769,7 +16788,7 @@ static struct hda_verb alc861vd_3stack_init_verbs[] = {
 /*
  * 6-stack pin configuration:
  */
-static struct hda_verb alc861vd_6stack_init_verbs[] = {
+static const struct hda_verb alc861vd_6stack_init_verbs[] = {
 	/*
 	 * Set pin mode and muting
 	 */
@@ -16810,18 +16829,18 @@ static struct hda_verb alc861vd_6stack_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb alc861vd_eapd_verbs[] = {
+static const struct hda_verb alc861vd_eapd_verbs[] = {
 	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{ }
 };
 
-static struct hda_verb alc660vd_eapd_verbs[] = {
+static const struct hda_verb alc660vd_eapd_verbs[] = {
 	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{ }
 };
 
-static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
+static const struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
@@ -16835,11 +16854,13 @@ static void alc861vd_lenovo_setup(struct hda_codec *codec)
 	struct alc_spec *spec = codec->spec;
 	spec->autocfg.hp_pins[0] = 0x1b;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
 {
-	alc_automute_amp(codec);
+	alc_hp_automute(codec);
 	alc88x_simple_mic_automute(codec);
 }
 
@@ -16851,12 +16872,12 @@ static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
 		alc88x_simple_mic_automute(codec);
 		break;
 	default:
-		alc_automute_amp_unsol_event(codec, res);
+		alc_sku_unsol_event(codec, res);
 		break;
 	}
 }
 
-static struct hda_verb alc861vd_dallas_verbs[] = {
+static const struct hda_verb alc861vd_dallas_verbs[] = {
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
@@ -16908,6 +16929,8 @@ static void alc861vd_dallas_setup(struct hda_codec *codec)
 
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -16936,7 +16959,7 @@ static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = {
 	[ALC861VD_AUTO]		= "auto",
 };
 
-static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
+static const struct snd_pci_quirk alc861vd_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
 	SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
 	SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
@@ -16955,7 +16978,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
 	{}
 };
 
-static struct alc_config_preset alc861vd_presets[] = {
+static const struct alc_config_preset alc861vd_presets[] = {
 	[ALC660VD_3ST] = {
 		.mixers = { alc861vd_3st_mixer },
 		.init_verbs = { alc861vd_volume_init_verbs,
@@ -17032,9 +17055,9 @@ static struct alc_config_preset alc861vd_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
 		.channel_mode = alc861vd_3stack_2ch_modes,
 		.input_mux = &alc861vd_dallas_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc861vd_dallas_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC861VD_HP] = {
 		.mixers = { alc861vd_hp_mixer },
@@ -17045,9 +17068,9 @@ static struct alc_config_preset alc861vd_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
 		.channel_mode = alc861vd_3stack_2ch_modes,
 		.input_mux = &alc861vd_hp_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc861vd_dallas_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	[ALC660VD_ASUS_V1S] = {
 		.mixers = { alc861vd_lenovo_mixer },
@@ -17146,11 +17169,15 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
 	static const char * const chname[4] = {
 		"Front", "Surround", "CLFE", "Side"
 	};
-	const char *pfx = alc_get_line_out_pfx(cfg, true);
+	const char *pfx = alc_get_line_out_pfx(spec, true);
 	hda_nid_t nid_v, nid_s;
-	int i, err;
+	int i, err, noutputs;
 
-	for (i = 0; i < cfg->line_outs; i++) {
+	noutputs = cfg->line_outs;
+	if (spec->multi_ios > 0)
+		noutputs += spec->multi_ios;
+
+	for (i = 0; i < noutputs; i++) {
 		if (!spec->multiout.dac_nids[i])
 			continue;
 		nid_v = alc861vd_idx_to_mixer_vol(
@@ -17263,7 +17290,7 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 	int err;
-	static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
+	static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
 
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 					   alc861vd_ignore);
@@ -17275,6 +17302,9 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec)
 	err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
 	if (err < 0)
 		return err;
+	err = alc_auto_add_multi_channel_mode(codec);
+	if (err < 0)
+		return err;
 	err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
 	if (err < 0)
 		return err;
@@ -17343,7 +17373,7 @@ static const struct alc_fixup alc861vd_fixups[] = {
 	},
 };
 
-static struct snd_pci_quirk alc861vd_fixup_tbl[] = {
+static const struct snd_pci_quirk alc861vd_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
 	{}
 };
@@ -17426,6 +17456,7 @@ static int patch_alc861vd(struct hda_codec *codec)
 
 	if (board_config == ALC861VD_AUTO)
 		spec->init_hook = alc861vd_auto_init;
+	spec->shutup = alc_eapd_shutup;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	if (!spec->loopback.amplist)
 		spec->loopback.amplist = alc861vd_loopbacks;
@@ -17448,32 +17479,32 @@ static int patch_alc861vd(struct hda_codec *codec)
 #define ALC662_DIGOUT_NID	0x06
 #define ALC662_DIGIN_NID	0x0a
 
-static hda_nid_t alc662_dac_nids[4] = {
-	/* front, rear, clfe, rear_surr */
+static const hda_nid_t alc662_dac_nids[3] = {
+	/* front, rear, clfe */
 	0x02, 0x03, 0x04
 };
 
-static hda_nid_t alc272_dac_nids[2] = {
+static const hda_nid_t alc272_dac_nids[2] = {
 	0x02, 0x03
 };
 
-static hda_nid_t alc662_adc_nids[2] = {
+static const hda_nid_t alc662_adc_nids[2] = {
 	/* ADC1-2 */
 	0x09, 0x08
 };
 
-static hda_nid_t alc272_adc_nids[1] = {
+static const hda_nid_t alc272_adc_nids[1] = {
 	/* ADC1-2 */
 	0x08,
 };
 
-static hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
-static hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
+static const hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
+static const hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
 
 
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
-static struct hda_input_mux alc662_capture_source = {
+static const struct hda_input_mux alc662_capture_source = {
 	.num_items = 4,
 	.items = {
 		{ "Mic", 0x0 },
@@ -17483,7 +17514,7 @@ static struct hda_input_mux alc662_capture_source = {
 	},
 };
 
-static struct hda_input_mux alc662_lenovo_101e_capture_source = {
+static const struct hda_input_mux alc662_lenovo_101e_capture_source = {
 	.num_items = 2,
 	.items = {
 		{ "Mic", 0x1 },
@@ -17491,7 +17522,7 @@ static struct hda_input_mux alc662_lenovo_101e_capture_source = {
 	},
 };
 
-static struct hda_input_mux alc663_capture_source = {
+static const struct hda_input_mux alc663_capture_source = {
 	.num_items = 3,
 	.items = {
 		{ "Mic", 0x0 },
@@ -17501,7 +17532,7 @@ static struct hda_input_mux alc663_capture_source = {
 };
 
 #if 0 /* set to 1 for testing other input sources below */
-static struct hda_input_mux alc272_nc10_capture_source = {
+static const struct hda_input_mux alc272_nc10_capture_source = {
 	.num_items = 16,
 	.items = {
 		{ "Autoselect Mic", 0x0 },
@@ -17527,14 +17558,14 @@ static struct hda_input_mux alc272_nc10_capture_source = {
 /*
  * 2ch mode
  */
-static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
+static const struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
 	{ 2, NULL }
 };
 
 /*
  * 2ch mode
  */
-static struct hda_verb alc662_3ST_ch2_init[] = {
+static const struct hda_verb alc662_3ST_ch2_init[] = {
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
@@ -17545,7 +17576,7 @@ static struct hda_verb alc662_3ST_ch2_init[] = {
 /*
  * 6ch mode
  */
-static struct hda_verb alc662_3ST_ch6_init[] = {
+static const struct hda_verb alc662_3ST_ch6_init[] = {
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
@@ -17555,7 +17586,7 @@ static struct hda_verb alc662_3ST_ch6_init[] = {
 	{ } /* end */
 };
 
-static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
+static const struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
 	{ 2, alc662_3ST_ch2_init },
 	{ 6, alc662_3ST_ch6_init },
 };
@@ -17563,7 +17594,7 @@ static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
 /*
  * 2ch mode
  */
-static struct hda_verb alc662_sixstack_ch6_init[] = {
+static const struct hda_verb alc662_sixstack_ch6_init[] = {
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
 	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -17573,14 +17604,14 @@ static struct hda_verb alc662_sixstack_ch6_init[] = {
 /*
  * 6ch mode
  */
-static struct hda_verb alc662_sixstack_ch8_init[] = {
+static const struct hda_verb alc662_sixstack_ch8_init[] = {
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ } /* end */
 };
 
-static struct hda_channel_mode alc662_5stack_modes[2] = {
+static const struct hda_channel_mode alc662_5stack_modes[2] = {
 	{ 2, alc662_sixstack_ch6_init },
 	{ 6, alc662_sixstack_ch8_init },
 };
@@ -17589,7 +17620,7 @@ static struct hda_channel_mode alc662_5stack_modes[2] = {
  *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
  */
 
-static struct snd_kcontrol_new alc662_base_mixer[] = {
+static const struct snd_kcontrol_new alc662_base_mixer[] = {
 	/* output mixer control */
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
@@ -17613,7 +17644,7 @@ static struct snd_kcontrol_new alc662_base_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
+static const struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
@@ -17628,7 +17659,7 @@ static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
+static const struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
@@ -17649,7 +17680,7 @@ static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
+static const struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
@@ -17662,7 +17693,7 @@ static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
+static const struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	ALC262_HIPPO_MASTER_SWITCH,
 
@@ -17676,7 +17707,7 @@ static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
+static const struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
 	ALC262_HIPPO_MASTER_SWITCH,
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
@@ -17690,7 +17721,7 @@ static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_bind_ctls alc663_asus_bind_master_vol = {
+static const struct hda_bind_ctls alc663_asus_bind_master_vol = {
 	.ops = &snd_hda_bind_vol,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
@@ -17699,7 +17730,7 @@ static struct hda_bind_ctls alc663_asus_bind_master_vol = {
 	},
 };
 
-static struct hda_bind_ctls alc663_asus_one_bind_switch = {
+static const struct hda_bind_ctls alc663_asus_one_bind_switch = {
 	.ops = &snd_hda_bind_sw,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
@@ -17708,7 +17739,7 @@ static struct hda_bind_ctls alc663_asus_one_bind_switch = {
 	},
 };
 
-static struct snd_kcontrol_new alc663_m51va_mixer[] = {
+static const struct snd_kcontrol_new alc663_m51va_mixer[] = {
 	HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
 	HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -17716,7 +17747,7 @@ static struct snd_kcontrol_new alc663_m51va_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
+static const struct hda_bind_ctls alc663_asus_tree_bind_switch = {
 	.ops = &snd_hda_bind_sw,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
@@ -17726,7 +17757,7 @@ static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
 	},
 };
 
-static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
+static const struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
 	HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
 	HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -17737,7 +17768,7 @@ static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_bind_ctls alc663_asus_four_bind_switch = {
+static const struct hda_bind_ctls alc663_asus_four_bind_switch = {
 	.ops = &snd_hda_bind_sw,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
@@ -17747,7 +17778,7 @@ static struct hda_bind_ctls alc663_asus_four_bind_switch = {
 	},
 };
 
-static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
+static const struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
 	HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
 	HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -17757,7 +17788,7 @@ static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
+static const struct snd_kcontrol_new alc662_1bjd_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
@@ -17768,7 +17799,7 @@ static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
+static const struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
 	.ops = &snd_hda_bind_vol,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
@@ -17777,7 +17808,7 @@ static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
 	},
 };
 
-static struct hda_bind_ctls alc663_asus_two_bind_switch = {
+static const struct hda_bind_ctls alc663_asus_two_bind_switch = {
 	.ops = &snd_hda_bind_sw,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
@@ -17786,7 +17817,7 @@ static struct hda_bind_ctls alc663_asus_two_bind_switch = {
 	},
 };
 
-static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
+static const struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
 	HDA_BIND_VOL("Master Playback Volume",
 				&alc663_asus_two_bind_master_vol),
 	HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
@@ -17797,7 +17828,7 @@ static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
+static const struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
 	HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
 	HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
@@ -17807,7 +17838,7 @@ static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc663_g71v_mixer[] = {
+static const struct snd_kcontrol_new alc663_g71v_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
@@ -17821,7 +17852,7 @@ static struct snd_kcontrol_new alc663_g71v_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc663_g50v_mixer[] = {
+static const struct snd_kcontrol_new alc663_g50v_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
@@ -17835,7 +17866,7 @@ static struct snd_kcontrol_new alc663_g50v_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
+static const struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
 	.ops = &snd_hda_bind_sw,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
@@ -17847,7 +17878,7 @@ static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
 	},
 };
 
-static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
+static const struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
 	.ops = &snd_hda_bind_sw,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
@@ -17856,7 +17887,7 @@ static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
 	},
 };
 
-static struct snd_kcontrol_new alc663_mode7_mixer[] = {
+static const struct snd_kcontrol_new alc663_mode7_mixer[] = {
 	HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
 	HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
 	HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
@@ -17869,7 +17900,7 @@ static struct snd_kcontrol_new alc663_mode7_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc663_mode8_mixer[] = {
+static const struct snd_kcontrol_new alc663_mode8_mixer[] = {
 	HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
 	HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
 	HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
@@ -17881,7 +17912,7 @@ static struct snd_kcontrol_new alc663_mode8_mixer[] = {
 };
 
 
-static struct snd_kcontrol_new alc662_chmode_mixer[] = {
+static const struct snd_kcontrol_new alc662_chmode_mixer[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Channel Mode",
@@ -17892,7 +17923,7 @@ static struct snd_kcontrol_new alc662_chmode_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb alc662_init_verbs[] = {
+static const struct hda_verb alc662_init_verbs[] = {
 	/* ADC: mute amp left and right */
 	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -17938,55 +17969,36 @@ static struct hda_verb alc662_init_verbs[] = {
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 
-	/* always trun on EAPD */
-	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
-
-	{ }
-};
-
-static struct hda_verb alc663_init_verbs[] = {
-	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{ }
 };
 
-static struct hda_verb alc272_init_verbs[] = {
-	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+static const struct hda_verb alc662_eapd_init_verbs[] = {
+	/* always trun on EAPD */
+	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{ }
 };
 
-static struct hda_verb alc662_sue_init_verbs[] = {
+static const struct hda_verb alc662_sue_init_verbs[] = {
 	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
 	{}
 };
 
-static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
+static const struct hda_verb alc662_eeepc_sue_init_verbs[] = {
 	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{}
 };
 
 /* Set Unsolicited Event*/
-static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
+static const struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{}
 };
 
-static struct hda_verb alc663_m51va_init_verbs[] = {
+static const struct hda_verb alc663_m51va_init_verbs[] = {
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -17999,7 +18011,7 @@ static struct hda_verb alc663_m51va_init_verbs[] = {
 	{}
 };
 
-static struct hda_verb alc663_21jd_amic_init_verbs[] = {
+static const struct hda_verb alc663_21jd_amic_init_verbs[] = {
 	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x21, AC_VERB_SET_CONNECT_SEL, 0x01},	/* Headphone */
@@ -18010,7 +18022,7 @@ static struct hda_verb alc663_21jd_amic_init_verbs[] = {
 	{}
 };
 
-static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
+static const struct hda_verb alc662_1bjd_amic_init_verbs[] = {
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -18022,7 +18034,7 @@ static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
 	{}
 };
 
-static struct hda_verb alc663_15jd_amic_init_verbs[] = {
+static const struct hda_verb alc663_15jd_amic_init_verbs[] = {
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},	/* Headphone */
@@ -18033,7 +18045,7 @@ static struct hda_verb alc663_15jd_amic_init_verbs[] = {
 	{}
 };
 
-static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
+static const struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -18049,7 +18061,7 @@ static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
 	{}
 };
 
-static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
+static const struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -18065,7 +18077,7 @@ static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
 	{}
 };
 
-static struct hda_verb alc663_g71v_init_verbs[] = {
+static const struct hda_verb alc663_g71v_init_verbs[] = {
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	/* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
 	/* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
@@ -18080,7 +18092,7 @@ static struct hda_verb alc663_g71v_init_verbs[] = {
 	{}
 };
 
-static struct hda_verb alc663_g50v_init_verbs[] = {
+static const struct hda_verb alc663_g50v_init_verbs[] = {
 	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x21, AC_VERB_SET_CONNECT_SEL, 0x00},	/* Headphone */
@@ -18090,7 +18102,7 @@ static struct hda_verb alc663_g50v_init_verbs[] = {
 	{}
 };
 
-static struct hda_verb alc662_ecs_init_verbs[] = {
+static const struct hda_verb alc662_ecs_init_verbs[] = {
 	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
@@ -18098,7 +18110,7 @@ static struct hda_verb alc662_ecs_init_verbs[] = {
 	{}
 };
 
-static struct hda_verb alc272_dell_zm1_init_verbs[] = {
+static const struct hda_verb alc272_dell_zm1_init_verbs[] = {
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
@@ -18113,7 +18125,7 @@ static struct hda_verb alc272_dell_zm1_init_verbs[] = {
 	{}
 };
 
-static struct hda_verb alc272_dell_init_verbs[] = {
+static const struct hda_verb alc272_dell_init_verbs[] = {
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
@@ -18128,7 +18140,7 @@ static struct hda_verb alc272_dell_init_verbs[] = {
 	{}
 };
 
-static struct hda_verb alc663_mode7_init_verbs[] = {
+static const struct hda_verb alc663_mode7_init_verbs[] = {
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
@@ -18147,7 +18159,7 @@ static struct hda_verb alc663_mode7_init_verbs[] = {
 	{}
 };
 
-static struct hda_verb alc663_mode8_init_verbs[] = {
+static const struct hda_verb alc663_mode8_init_verbs[] = {
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -18167,61 +18179,29 @@ static struct hda_verb alc663_mode8_init_verbs[] = {
 	{}
 };
 
-static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
+static const struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
+static const struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
 	{ } /* end */
 };
 
-static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_jack_detect(codec, 0x14);
-	bits = present ? HDA_AMP_MUTE : 0;
-
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-}
-
-static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-	unsigned char bits;
-
- 	present = snd_hda_jack_detect(codec, 0x1b);
-	bits = present ? HDA_AMP_MUTE : 0;
-
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-}
-
-static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
+static void alc662_lenovo_101e_setup(struct hda_codec *codec)
 {
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc662_lenovo_101e_all_automute(codec);
-	if ((res >> 26) == ALC880_FRONT_EVENT)
-		alc662_lenovo_101e_ispeaker_automute(codec);
-}
+	struct alc_spec *spec = codec->spec;
 
-/* unsolicited event for HP jack sensing */
-static void alc662_eeepc_unsol_event(struct hda_codec *codec,
-				     unsigned int res)
-{
-	if ((res >> 26) == ALC880_MIC_EVENT)
-		alc_mic_automute(codec);
-	else
-		alc262_hippo_unsol_event(codec, res);
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.line_out_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[0] = 0x15;
+	spec->automute = 1;
+	spec->detect_line = 1;
+	spec->automute_lines = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 static void alc662_eeepc_setup(struct hda_codec *codec)
@@ -18236,180 +18216,24 @@ static void alc662_eeepc_setup(struct hda_codec *codec)
 	spec->auto_mic = 1;
 }
 
-static void alc662_eeepc_inithook(struct hda_codec *codec)
-{
-	alc262_hippo_automute(codec);
-	alc_mic_automute(codec);
-}
-
 static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x1b;
-}
-
-#define alc662_eeepc_ep20_inithook	alc262_hippo_master_update
-
-static void alc663_m51va_speaker_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_jack_detect(codec, 0x21);
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
-				 HDA_AMP_MUTE, bits);
-}
-
-static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_jack_detect(codec, 0x21);
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
-				 HDA_AMP_MUTE, bits);
-}
-
-static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_jack_detect(codec, 0x15);
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
-				 HDA_AMP_MUTE, bits);
-}
-
-static void alc662_f5z_speaker_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_jack_detect(codec, 0x1b);
-	bits = present ? 0 : PIN_OUT;
-	snd_hda_codec_write(codec, 0x14, 0,
-			 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
-}
-
-static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
-{
-	unsigned int present1, present2;
-
-	present1 = snd_hda_jack_detect(codec, 0x21);
-	present2 = snd_hda_jack_detect(codec, 0x15);
-
-	if (present1 || present2) {
-		snd_hda_codec_write_cache(codec, 0x14, 0,
-			AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
-	} else {
-		snd_hda_codec_write_cache(codec, 0x14, 0,
-			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-	}
-}
-
-static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
-{
-	unsigned int present1, present2;
-
-	present1 = snd_hda_jack_detect(codec, 0x1b);
-	present2 = snd_hda_jack_detect(codec, 0x15);
-
-	if (present1 || present2) {
-		snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
-		snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
-	} else {
-		snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
-					 HDA_AMP_MUTE, 0);
-		snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
-					 HDA_AMP_MUTE, 0);
-	}
-}
-
-static void alc663_two_hp_m7_speaker_automute(struct hda_codec *codec)
-{
-	unsigned int present1, present2;
-
-	present1 = snd_hda_codec_read(codec, 0x1b, 0,
-			AC_VERB_GET_PIN_SENSE, 0)
-			& AC_PINSENSE_PRESENCE;
-	present2 = snd_hda_codec_read(codec, 0x21, 0,
-			AC_VERB_GET_PIN_SENSE, 0)
-			& AC_PINSENSE_PRESENCE;
-
-	if (present1 || present2) {
-		snd_hda_codec_write_cache(codec, 0x14, 0,
-			AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
-		snd_hda_codec_write_cache(codec, 0x17, 0,
-			AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
-	} else {
-		snd_hda_codec_write_cache(codec, 0x14, 0,
-			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-		snd_hda_codec_write_cache(codec, 0x17, 0,
-			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-	}
-}
-
-static void alc663_two_hp_m8_speaker_automute(struct hda_codec *codec)
-{
-	unsigned int present1, present2;
-
-	present1 = snd_hda_codec_read(codec, 0x21, 0,
-			AC_VERB_GET_PIN_SENSE, 0)
-			& AC_PINSENSE_PRESENCE;
-	present2 = snd_hda_codec_read(codec, 0x15, 0,
-			AC_VERB_GET_PIN_SENSE, 0)
-			& AC_PINSENSE_PRESENCE;
-
-	if (present1 || present2) {
-		snd_hda_codec_write_cache(codec, 0x14, 0,
-			AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
-		snd_hda_codec_write_cache(codec, 0x17, 0,
-			AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
-	} else {
-		snd_hda_codec_write_cache(codec, 0x14, 0,
-			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-		snd_hda_codec_write_cache(codec, 0x17, 0,
-			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-	}
-}
-
-static void alc663_m51va_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
-{
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc663_m51va_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 static void alc663_m51va_setup(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x21;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.mux_idx = 0;
 	spec->int_mic.pin = 0x12;
@@ -18417,18 +18241,15 @@ static void alc663_m51va_setup(struct hda_codec *codec)
 	spec->auto_mic = 1;
 }
 
-static void alc663_m51va_inithook(struct hda_codec *codec)
-{
-	alc663_m51va_speaker_automute(codec);
-	alc_mic_automute(codec);
-}
-
 /* ***************** Mode1 ******************************/
-#define alc663_mode1_unsol_event	alc663_m51va_unsol_event
-
 static void alc663_mode1_setup(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x21;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.mux_idx = 0;
 	spec->int_mic.pin = 0x19;
@@ -18436,229 +18257,144 @@ static void alc663_mode1_setup(struct hda_codec *codec)
 	spec->auto_mic = 1;
 }
 
-#define alc663_mode1_inithook		alc663_m51va_inithook
-
 /* ***************** Mode2 ******************************/
-static void alc662_mode2_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
+static void alc662_mode2_setup(struct hda_codec *codec)
 {
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc662_f5z_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
+	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
+	spec->ext_mic.pin = 0x18;
+	spec->ext_mic.mux_idx = 0;
+	spec->int_mic.pin = 0x19;
+	spec->int_mic.mux_idx = 1;
+	spec->auto_mic = 1;
 }
 
-#define alc662_mode2_setup	alc663_mode1_setup
-
-static void alc662_mode2_inithook(struct hda_codec *codec)
-{
-	alc662_f5z_speaker_automute(codec);
-	alc_mic_automute(codec);
-}
 /* ***************** Mode3 ******************************/
-static void alc663_mode3_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
+static void alc663_mode3_setup(struct hda_codec *codec)
 {
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc663_two_hp_m1_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
+	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x21;
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
+	spec->ext_mic.pin = 0x18;
+	spec->ext_mic.mux_idx = 0;
+	spec->int_mic.pin = 0x19;
+	spec->int_mic.mux_idx = 1;
+	spec->auto_mic = 1;
 }
 
-#define alc663_mode3_setup	alc663_mode1_setup
-
-static void alc663_mode3_inithook(struct hda_codec *codec)
-{
-	alc663_two_hp_m1_speaker_automute(codec);
-	alc_mic_automute(codec);
-}
 /* ***************** Mode4 ******************************/
-static void alc663_mode4_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
+static void alc663_mode4_setup(struct hda_codec *codec)
 {
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc663_21jd_two_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
+	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x21;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[1] = 0x16;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute_mixer_nid[1] = 0x0e;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
+	spec->ext_mic.pin = 0x18;
+	spec->ext_mic.mux_idx = 0;
+	spec->int_mic.pin = 0x19;
+	spec->int_mic.mux_idx = 1;
+	spec->auto_mic = 1;
 }
 
-#define alc663_mode4_setup	alc663_mode1_setup
-
-static void alc663_mode4_inithook(struct hda_codec *codec)
-{
-	alc663_21jd_two_speaker_automute(codec);
-	alc_mic_automute(codec);
-}
 /* ***************** Mode5 ******************************/
-static void alc663_mode5_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
+static void alc663_mode5_setup(struct hda_codec *codec)
 {
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc663_15jd_two_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
+	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[1] = 0x16;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute_mixer_nid[1] = 0x0e;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
+	spec->ext_mic.pin = 0x18;
+	spec->ext_mic.mux_idx = 0;
+	spec->int_mic.pin = 0x19;
+	spec->int_mic.mux_idx = 1;
+	spec->auto_mic = 1;
 }
 
-#define alc663_mode5_setup	alc663_mode1_setup
-
-static void alc663_mode5_inithook(struct hda_codec *codec)
-{
-	alc663_15jd_two_speaker_automute(codec);
-	alc_mic_automute(codec);
-}
 /* ***************** Mode6 ******************************/
-static void alc663_mode6_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
+static void alc663_mode6_setup(struct hda_codec *codec)
 {
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc663_two_hp_m2_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
-}
-
-#define alc663_mode6_setup	alc663_mode1_setup
-
-static void alc663_mode6_inithook(struct hda_codec *codec)
-{
-	alc663_two_hp_m2_speaker_automute(codec);
-	alc_mic_automute(codec);
+	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
+	spec->ext_mic.pin = 0x18;
+	spec->ext_mic.mux_idx = 0;
+	spec->int_mic.pin = 0x19;
+	spec->int_mic.mux_idx = 1;
+	spec->auto_mic = 1;
 }
 
 /* ***************** Mode7 ******************************/
-static void alc663_mode7_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
-{
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc663_two_hp_m7_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
-}
-
-#define alc663_mode7_setup	alc663_mode1_setup
-
-static void alc663_mode7_inithook(struct hda_codec *codec)
+static void alc663_mode7_setup(struct hda_codec *codec)
 {
-	alc663_two_hp_m7_speaker_automute(codec);
-	alc_mic_automute(codec);
+	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.hp_pins[0] = 0x21;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[0] = 0x17;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
+	spec->ext_mic.pin = 0x18;
+	spec->ext_mic.mux_idx = 0;
+	spec->int_mic.pin = 0x19;
+	spec->int_mic.mux_idx = 1;
+	spec->auto_mic = 1;
 }
 
 /* ***************** Mode8 ******************************/
-static void alc663_mode8_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
-{
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc663_two_hp_m8_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
-}
-
-#define alc663_mode8_setup	alc663_m51va_setup
-
-static void alc663_mode8_inithook(struct hda_codec *codec)
-{
-	alc663_two_hp_m8_speaker_automute(codec);
-	alc_mic_automute(codec);
-}
-
-static void alc663_g71v_hp_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_jack_detect(codec, 0x21);
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-}
-
-static void alc663_g71v_front_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_jack_detect(codec, 0x15);
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-}
-
-static void alc663_g71v_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
+static void alc663_mode8_setup(struct hda_codec *codec)
 {
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc663_g71v_hp_automute(codec);
-		break;
-	case ALC880_FRONT_EVENT:
-		alc663_g71v_front_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
-}
-
-#define alc663_g71v_setup	alc663_m51va_setup
-
-static void alc663_g71v_inithook(struct hda_codec *codec)
-{
-	alc663_g71v_front_automute(codec);
-	alc663_g71v_hp_automute(codec);
-	alc_mic_automute(codec);
+	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x21;
+	spec->autocfg.hp_pins[1] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[0] = 0x17;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
+	spec->ext_mic.pin = 0x18;
+	spec->ext_mic.mux_idx = 0;
+	spec->int_mic.pin = 0x12;
+	spec->int_mic.mux_idx = 9;
+	spec->auto_mic = 1;
 }
 
-static void alc663_g50v_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
+static void alc663_g71v_setup(struct hda_codec *codec)
 {
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc663_m51va_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
+	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x21;
+	spec->autocfg.line_out_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
+	spec->detect_line = 1;
+	spec->automute_lines = 1;
+	spec->ext_mic.pin = 0x18;
+	spec->ext_mic.mux_idx = 0;
+	spec->int_mic.pin = 0x12;
+	spec->int_mic.mux_idx = 9;
+	spec->auto_mic = 1;
 }
 
 #define alc663_g50v_setup	alc663_m51va_setup
 
-static void alc663_g50v_inithook(struct hda_codec *codec)
-{
-	alc663_m51va_speaker_automute(codec);
-	alc_mic_automute(codec);
-}
-
-static struct snd_kcontrol_new alc662_ecs_mixer[] = {
+static const struct snd_kcontrol_new alc662_ecs_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	ALC262_HIPPO_MASTER_SWITCH,
 
@@ -18672,7 +18408,7 @@ static struct snd_kcontrol_new alc662_ecs_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc272_nc10_mixer[] = {
+static const struct snd_kcontrol_new alc272_nc10_mixer[] = {
 	/* Master Playback automatically created from Speaker and Headphone */
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -18707,7 +18443,7 @@ static const char * const alc662_models[ALC662_MODEL_LAST] = {
 	[ALC662_3ST_2ch_DIG]	= "3stack-dig",
 	[ALC662_3ST_6ch_DIG]	= "3stack-6ch-dig",
 	[ALC662_3ST_6ch]	= "3stack-6ch",
-	[ALC662_5ST_DIG]	= "6stack-dig",
+	[ALC662_5ST_DIG]	= "5stack-dig",
 	[ALC662_LENOVO_101E]	= "lenovo-101e",
 	[ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
 	[ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
@@ -18730,7 +18466,7 @@ static const char * const alc662_models[ALC662_MODEL_LAST] = {
 	[ALC662_AUTO]		= "auto",
 };
 
-static struct snd_pci_quirk alc662_cfg_tbl[] = {
+static const struct snd_pci_quirk alc662_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
 	SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
 	SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
@@ -18812,10 +18548,10 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = {
 	{}
 };
 
-static struct alc_config_preset alc662_presets[] = {
+static const struct alc_config_preset alc662_presets[] = {
 	[ALC662_3ST_2ch_DIG] = {
 		.mixers = { alc662_3ST_2ch_mixer },
-		.init_verbs = { alc662_init_verbs },
+		.init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dig_out_nid = ALC662_DIGOUT_NID,
@@ -18826,7 +18562,7 @@ static struct alc_config_preset alc662_presets[] = {
 	},
 	[ALC662_3ST_6ch_DIG] = {
 		.mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
-		.init_verbs = { alc662_init_verbs },
+		.init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dig_out_nid = ALC662_DIGOUT_NID,
@@ -18838,7 +18574,7 @@ static struct alc_config_preset alc662_presets[] = {
 	},
 	[ALC662_3ST_6ch] = {
 		.mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
-		.init_verbs = { alc662_init_verbs },
+		.init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
@@ -18848,7 +18584,7 @@ static struct alc_config_preset alc662_presets[] = {
 	},
 	[ALC662_5ST_DIG] = {
 		.mixers = { alc662_base_mixer, alc662_chmode_mixer },
-		.init_verbs = { alc662_init_verbs },
+		.init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dig_out_nid = ALC662_DIGOUT_NID,
@@ -18859,104 +18595,120 @@ static struct alc_config_preset alc662_presets[] = {
 	},
 	[ALC662_LENOVO_101E] = {
 		.mixers = { alc662_lenovo_101e_mixer },
-		.init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
+		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
+				alc662_sue_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
 		.input_mux = &alc662_lenovo_101e_capture_source,
-		.unsol_event = alc662_lenovo_101e_unsol_event,
-		.init_hook = alc662_lenovo_101e_all_automute,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc662_lenovo_101e_setup,
+		.init_hook = alc_inithook,
 	},
 	[ALC662_ASUS_EEEPC_P701] = {
 		.mixers = { alc662_eeepc_p701_mixer },
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc662_eeepc_sue_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc662_eeepc_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc662_eeepc_setup,
-		.init_hook = alc662_eeepc_inithook,
+		.init_hook = alc_inithook,
 	},
 	[ALC662_ASUS_EEEPC_EP20] = {
 		.mixers = { alc662_eeepc_ep20_mixer,
 			    alc662_chmode_mixer },
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc662_eeepc_ep20_sue_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
 		.channel_mode = alc662_3ST_6ch_modes,
 		.input_mux = &alc662_lenovo_101e_capture_source,
-		.unsol_event = alc662_eeepc_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc662_eeepc_ep20_setup,
-		.init_hook = alc662_eeepc_ep20_inithook,
+		.init_hook = alc_inithook,
 	},
 	[ALC662_ECS] = {
 		.mixers = { alc662_ecs_mixer },
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc662_ecs_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc662_eeepc_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc662_eeepc_setup,
-		.init_hook = alc662_eeepc_inithook,
+		.init_hook = alc_inithook,
 	},
 	[ALC663_ASUS_M51VA] = {
 		.mixers = { alc663_m51va_mixer },
-		.init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
+		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
+				alc663_m51va_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_m51va_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_m51va_setup,
-		.init_hook = alc663_m51va_inithook,
+		.init_hook = alc_inithook,
 	},
 	[ALC663_ASUS_G71V] = {
 		.mixers = { alc663_g71v_mixer },
-		.init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
+		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
+				alc663_g71v_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_g71v_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_g71v_setup,
-		.init_hook = alc663_g71v_inithook,
+		.init_hook = alc_inithook,
 	},
 	[ALC663_ASUS_H13] = {
 		.mixers = { alc663_m51va_mixer },
-		.init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
+		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
+				alc663_m51va_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_m51va_unsol_event,
-		.init_hook = alc663_m51va_inithook,
+		.setup = alc663_m51va_setup,
+		.unsol_event = alc_sku_unsol_event,
+		.init_hook = alc_inithook,
 	},
 	[ALC663_ASUS_G50V] = {
 		.mixers = { alc663_g50v_mixer },
-		.init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
+		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
+				alc663_g50v_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
 		.channel_mode = alc662_3ST_6ch_modes,
 		.input_mux = &alc663_capture_source,
-		.unsol_event = alc663_g50v_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_g50v_setup,
-		.init_hook = alc663_g50v_inithook,
+		.init_hook = alc_inithook,
 	},
 	[ALC663_ASUS_MODE1] = {
 		.mixers = { alc663_m51va_mixer },
 		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc663_21jd_amic_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.hp_nid = 0x03,
@@ -18964,28 +18716,30 @@ static struct alc_config_preset alc662_presets[] = {
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_mode1_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_mode1_setup,
-		.init_hook = alc663_mode1_inithook,
+		.init_hook = alc_inithook,
 	},
 	[ALC662_ASUS_MODE2] = {
 		.mixers = { alc662_1bjd_mixer },
 		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc662_1bjd_amic_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc662_mode2_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc662_mode2_setup,
-		.init_hook = alc662_mode2_inithook,
+		.init_hook = alc_inithook,
 	},
 	[ALC663_ASUS_MODE3] = {
 		.mixers = { alc663_two_hp_m1_mixer },
 		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc663_two_hp_amic_m1_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.hp_nid = 0x03,
@@ -18993,14 +18747,15 @@ static struct alc_config_preset alc662_presets[] = {
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_mode3_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_mode3_setup,
-		.init_hook = alc663_mode3_inithook,
+		.init_hook = alc_inithook,
 	},
 	[ALC663_ASUS_MODE4] = {
 		.mixers = { alc663_asus_21jd_clfe_mixer },
 		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc663_21jd_amic_init_verbs},
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.hp_nid = 0x03,
@@ -19008,14 +18763,15 @@ static struct alc_config_preset alc662_presets[] = {
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_mode4_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_mode4_setup,
-		.init_hook = alc663_mode4_inithook,
+		.init_hook = alc_inithook,
 	},
 	[ALC663_ASUS_MODE5] = {
 		.mixers = { alc663_asus_15jd_clfe_mixer },
 		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc663_15jd_amic_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.hp_nid = 0x03,
@@ -19023,14 +18779,15 @@ static struct alc_config_preset alc662_presets[] = {
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_mode5_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_mode5_setup,
-		.init_hook = alc663_mode5_inithook,
+		.init_hook = alc_inithook,
 	},
 	[ALC663_ASUS_MODE6] = {
 		.mixers = { alc663_two_hp_m2_mixer },
 		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc663_two_hp_amic_m2_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.hp_nid = 0x03,
@@ -19038,14 +18795,15 @@ static struct alc_config_preset alc662_presets[] = {
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_mode6_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_mode6_setup,
-		.init_hook = alc663_mode6_inithook,
+		.init_hook = alc_inithook,
 	},
 	[ALC663_ASUS_MODE7] = {
 		.mixers = { alc663_mode7_mixer },
 		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc663_mode7_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.hp_nid = 0x03,
@@ -19053,14 +18811,15 @@ static struct alc_config_preset alc662_presets[] = {
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_mode7_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_mode7_setup,
-		.init_hook = alc663_mode7_inithook,
+		.init_hook = alc_inithook,
 	},
 	[ALC663_ASUS_MODE8] = {
 		.mixers = { alc663_mode8_mixer },
 		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc663_mode8_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.hp_nid = 0x03,
@@ -19068,52 +18827,57 @@ static struct alc_config_preset alc662_presets[] = {
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_mode8_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_mode8_setup,
-		.init_hook = alc663_mode8_inithook,
+		.init_hook = alc_inithook,
 	},
 	[ALC272_DELL] = {
 		.mixers = { alc663_m51va_mixer },
 		.cap_mixer = alc272_auto_capture_mixer,
-		.init_verbs = { alc662_init_verbs, alc272_dell_init_verbs },
+		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
+				alc272_dell_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc272_dac_nids),
-		.dac_nids = alc662_dac_nids,
+		.dac_nids = alc272_dac_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.adc_nids = alc272_adc_nids,
 		.num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
 		.capsrc_nids = alc272_capsrc_nids,
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_m51va_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_m51va_setup,
-		.init_hook = alc663_m51va_inithook,
+		.init_hook = alc_inithook,
 	},
 	[ALC272_DELL_ZM1] = {
 		.mixers = { alc663_m51va_mixer },
 		.cap_mixer = alc662_auto_capture_mixer,
-		.init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs },
+		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
+				alc272_dell_zm1_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc272_dac_nids),
-		.dac_nids = alc662_dac_nids,
+		.dac_nids = alc272_dac_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.adc_nids = alc662_adc_nids,
 		.num_adc_nids = 1,
 		.capsrc_nids = alc662_capsrc_nids,
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_m51va_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_m51va_setup,
-		.init_hook = alc663_m51va_inithook,
+		.init_hook = alc_inithook,
 	},
 	[ALC272_SAMSUNG_NC10] = {
 		.mixers = { alc272_nc10_mixer },
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc663_21jd_amic_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc272_dac_nids),
 		.dac_nids = alc272_dac_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
 		/*.input_mux = &alc272_nc10_capture_source,*/
-		.unsol_event = alc663_mode4_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_mode4_setup,
-		.init_hook = alc663_mode4_inithook,
+		.init_hook = alc_inithook,
 	},
 };
 
@@ -19123,45 +18887,79 @@ static struct alc_config_preset alc662_presets[] = {
  */
 
 /* convert from MIX nid to DAC */
-static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid)
-{
-	if (nid == 0x0f)
-		return 0x02;
-	else if (nid >= 0x0c && nid <= 0x0e)
-		return nid - 0x0c + 0x02;
-	else if (nid == 0x26) /* ALC887-VD has this DAC too */
-		return 0x25;
-	else
-		return 0;
+static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid)
+{
+	hda_nid_t list[5];
+	int i, num;
+
+	num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list));
+	for (i = 0; i < num; i++) {
+		if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT)
+			return list[i];
+	}
+	return 0;
+}
+
+/* go down to the selector widget before the mixer */
+static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin)
+{
+	hda_nid_t srcs[5];
+	int num = snd_hda_get_connections(codec, pin, srcs,
+					  ARRAY_SIZE(srcs));
+	if (num != 1 ||
+	    get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL)
+		return pin;
+	return srcs[0];
 }
 
 /* get MIX nid connected to the given pin targeted to DAC */
-static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
+static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
 				   hda_nid_t dac)
 {
 	hda_nid_t mix[5];
 	int i, num;
 
+	pin = alc_go_down_to_selector(codec, pin);
 	num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
 	for (i = 0; i < num; i++) {
-		if (alc662_mix_to_dac(mix[i]) == dac)
+		if (alc_auto_mix_to_dac(codec, mix[i]) == dac)
 			return mix[i];
 	}
 	return 0;
 }
 
+/* select the connection from pin to DAC if needed */
+static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin,
+			       hda_nid_t dac)
+{
+	hda_nid_t mix[5];
+	int i, num;
+
+	pin = alc_go_down_to_selector(codec, pin);
+	num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
+	if (num < 2)
+		return 0;
+	for (i = 0; i < num; i++) {
+		if (alc_auto_mix_to_dac(codec, mix[i]) == dac) {
+			snd_hda_codec_update_cache(codec, pin, 0,
+						   AC_VERB_SET_CONNECT_SEL, i);
+			return 0;
+		}
+	}
+	return 0;
+}
+
 /* look for an empty DAC slot */
-static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
+static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
 {
 	struct alc_spec *spec = codec->spec;
 	hda_nid_t srcs[5];
 	int i, j, num;
 
+	pin = alc_go_down_to_selector(codec, pin);
 	num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
-	if (num < 0)
-		return 0;
 	for (i = 0; i < num; i++) {
-		hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
+		hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
 		if (!nid)
 			continue;
 		for (j = 0; j < spec->multiout.num_dacs; j++)
@@ -19183,10 +18981,10 @@ static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
 
 	spec->multiout.dac_nids = spec->private_dac_nids;
 	for (i = 0; i < cfg->line_outs; i++) {
-		dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
+		dac = alc_auto_look_for_dac(codec, cfg->line_out_pins[i]);
 		if (!dac)
 			continue;
-		spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
+		spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
 	}
 	return 0;
 }
@@ -19222,15 +19020,23 @@ static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
 	static const char * const chname[4] = {
 		"Front", "Surround", NULL /*CLFE*/, "Side"
 	};
-	const char *pfx = alc_get_line_out_pfx(cfg, true);
-	hda_nid_t nid, mix;
-	int i, err;
+	const char *pfx = alc_get_line_out_pfx(spec, true);
+	hda_nid_t nid, mix, pin;
+	int i, err, noutputs;
 
-	for (i = 0; i < cfg->line_outs; i++) {
+	noutputs = cfg->line_outs;
+	if (spec->multi_ios > 0)
+		noutputs += spec->multi_ios;
+
+	for (i = 0; i < noutputs; i++) {
 		nid = spec->multiout.dac_nids[i];
 		if (!nid)
 			continue;
-		mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
+		if (i >= cfg->line_outs)
+			pin = spec->multi_io[i - 1].pin;
+		else
+			pin = cfg->line_out_pins[i];
+		mix = alc_auto_dac_to_mix(codec, pin, nid);
 		if (!mix)
 			continue;
 		if (!pfx && i == 2) {
@@ -19276,7 +19082,7 @@ static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
 
 	if (!pin)
 		return 0;
-	nid = alc662_look_for_dac(codec, pin);
+	nid = alc_auto_look_for_dac(codec, pin);
 	if (!nid) {
 		/* the corresponding DAC is already occupied */
 		if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
@@ -19286,7 +19092,7 @@ static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
 				   HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
 	}
 
-	mix = alc662_dac_to_mix(codec, pin, nid);
+	mix = alc_auto_dac_to_mix(codec, pin, nid);
 	if (!mix)
 		return 0;
 	err = alc662_add_vol_ctl(spec, pfx, nid, 3);
@@ -19310,14 +19116,21 @@ static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
 	hda_nid_t srcs[HDA_MAX_CONNECTIONS];
 
 	alc_set_pin_output(codec, nid, pin_type);
-	/* need the manual connection? */
 	num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
-	if (num <= 1)
-		return;
 	for (i = 0; i < num; i++) {
-		if (alc662_mix_to_dac(srcs[i]) != dac)
+		if (alc_auto_mix_to_dac(codec, srcs[i]) != dac)
 			continue;
-		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
+		/* need the manual connection? */
+		if (num > 1)
+			snd_hda_codec_write(codec, nid, 0,
+					    AC_VERB_SET_CONNECT_SEL, i);
+		/* unmute mixer widget inputs */
+		snd_hda_codec_write(codec, srcs[i], 0,
+				    AC_VERB_SET_AMP_GAIN_MUTE,
+				    AMP_IN_UNMUTE(0));
+		snd_hda_codec_write(codec, srcs[i], 0,
+				    AC_VERB_SET_AMP_GAIN_MUTE,
+				    AMP_IN_UNMUTE(1));
 		return;
 	}
 }
@@ -19374,11 +19187,164 @@ static void alc662_auto_init_analog_input(struct hda_codec *codec)
 
 #define alc662_auto_init_input_src	alc882_auto_init_input_src
 
+/*
+ * multi-io helper
+ */
+static int alc_auto_fill_multi_ios(struct hda_codec *codec,
+				   unsigned int location)
+{
+	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int type, i, num_pins = 0;
+
+	for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
+		for (i = 0; i < cfg->num_inputs; i++) {
+			hda_nid_t nid = cfg->inputs[i].pin;
+			hda_nid_t dac;
+			unsigned int defcfg, caps;
+			if (cfg->inputs[i].type != type)
+				continue;
+			defcfg = snd_hda_codec_get_pincfg(codec, nid);
+			if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
+				continue;
+			if (location && get_defcfg_location(defcfg) != location)
+				continue;
+			caps = snd_hda_query_pin_caps(codec, nid);
+			if (!(caps & AC_PINCAP_OUT))
+				continue;
+			dac = alc_auto_look_for_dac(codec, nid);
+			if (!dac)
+				continue;
+			spec->multi_io[num_pins].pin = nid;
+			spec->multi_io[num_pins].dac = dac;
+			num_pins++;
+			spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
+		}
+	}
+	spec->multiout.num_dacs = 1;
+	if (num_pins < 2)
+		return 0;
+	return num_pins;
+}
+
+static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = spec->multi_ios + 1;
+	if (uinfo->value.enumerated.item > spec->multi_ios)
+		uinfo->value.enumerated.item = spec->multi_ios;
+	sprintf(uinfo->value.enumerated.name, "%dch",
+		(uinfo->value.enumerated.item + 1) * 2);
+	return 0;
+}
+
+static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2;
+	return 0;
+}
+
+static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
+{
+	struct alc_spec *spec = codec->spec;
+	hda_nid_t nid = spec->multi_io[idx].pin;
+
+	if (!spec->multi_io[idx].ctl_in)
+		spec->multi_io[idx].ctl_in =
+			snd_hda_codec_read(codec, nid, 0,
+					   AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+	if (output) {
+		snd_hda_codec_update_cache(codec, nid, 0,
+					   AC_VERB_SET_PIN_WIDGET_CONTROL,
+					   PIN_OUT);
+		if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
+			snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
+						 HDA_AMP_MUTE, 0);
+		alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac);
+	} else {
+		if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
+			snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
+						 HDA_AMP_MUTE, HDA_AMP_MUTE);
+		snd_hda_codec_update_cache(codec, nid, 0,
+					   AC_VERB_SET_PIN_WIDGET_CONTROL,
+					   spec->multi_io[idx].ctl_in);
+	}
+	return 0;
+}
+
+static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	int i, ch;
+
+	ch = ucontrol->value.enumerated.item[0];
+	if (ch < 0 || ch > spec->multi_ios)
+		return -EINVAL;
+	if (ch == (spec->ext_channel_count - 1) / 2)
+		return 0;
+	spec->ext_channel_count = (ch + 1) * 2;
+	for (i = 0; i < spec->multi_ios; i++)
+		alc_set_multi_io(codec, i, i < ch);
+	spec->multiout.max_channels = spec->ext_channel_count;
+	return 1;
+}
+
+static const struct snd_kcontrol_new alc_auto_channel_mode_enum = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Channel Mode",
+	.info = alc_auto_ch_mode_info,
+	.get = alc_auto_ch_mode_get,
+	.put = alc_auto_ch_mode_put,
+};
+
+static int alc_auto_add_multi_channel_mode(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	unsigned int location, defcfg;
+	int num_pins;
+
+	if (cfg->line_outs != 1 ||
+	    cfg->line_out_type != AUTO_PIN_LINE_OUT)
+		return 0;
+
+	defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]);
+	location = get_defcfg_location(defcfg);
+
+	num_pins = alc_auto_fill_multi_ios(codec, location);
+	if (num_pins > 0) {
+		struct snd_kcontrol_new *knew;
+
+		knew = alc_kcontrol_new(spec);
+		if (!knew)
+			return -ENOMEM;
+		*knew = alc_auto_channel_mode_enum;
+		knew->name = kstrdup("Channel Mode", GFP_KERNEL);
+		if (!knew->name)
+			return -ENOMEM;
+
+		spec->multi_ios = num_pins;
+		spec->ext_channel_count = 2;
+		spec->multiout.num_dacs = num_pins + 1;
+	}
+	return 0;
+}
+
 static int alc662_parse_auto_config(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 	int err;
-	static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
+	static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
 
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 					   alc662_ignore);
@@ -19390,6 +19356,9 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
 	err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
 	if (err < 0)
 		return err;
+	err = alc_auto_add_multi_channel_mode(codec);
+	if (err < 0)
+		return err;
 	err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
 	if (err < 0)
 		return err;
@@ -19420,14 +19389,6 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
 	spec->num_mux_defs = 1;
 	spec->input_mux = &spec->private_imux[0];
 
-	add_verb(spec, alc662_init_verbs);
-	if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
-	    codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
-		add_verb(spec, alc663_init_verbs);
-
-	if (codec->vendor_id == 0x10ec0272)
-		add_verb(spec, alc272_init_verbs);
-
 	err = alc_auto_add_mic_boost(codec);
 	if (err < 0)
 		return err;
@@ -19508,7 +19469,7 @@ static const struct alc_fixup alc662_fixups[] = {
 	},
 };
 
-static struct snd_pci_quirk alc662_fixup_tbl[] = {
+static const struct snd_pci_quirk alc662_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
 	SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
 	SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
@@ -19626,6 +19587,7 @@ static int patch_alc662(struct hda_codec *codec)
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC662_AUTO)
 		spec->init_hook = alc662_auto_init;
+	spec->shutup = alc_eapd_shutup;
 
 	alc_init_jacks(codec);
 
@@ -19654,6 +19616,15 @@ static int patch_alc888(struct hda_codec *codec)
 	return patch_alc882(codec);
 }
 
+static int patch_alc899(struct hda_codec *codec)
+{
+	if ((alc_read_coef_idx(codec, 0) & 0x2000) != 0x2000) {
+		kfree(codec->chip_name);
+		codec->chip_name = kstrdup("ALC898", GFP_KERNEL);
+	}
+	return patch_alc882(codec);
+}
+
 /*
  * ALC680 support
  */
@@ -19661,12 +19632,12 @@ static int patch_alc888(struct hda_codec *codec)
 #define ALC680_DIGOUT_NID	ALC880_DIGOUT_NID
 #define alc680_modes		alc260_modes
 
-static hda_nid_t alc680_dac_nids[3] = {
+static const hda_nid_t alc680_dac_nids[3] = {
 	/* Lout1, Lout2, hp */
 	0x02, 0x03, 0x04
 };
 
-static hda_nid_t alc680_adc_nids[3] = {
+static const hda_nid_t alc680_adc_nids[3] = {
 	/* ADC0-2 */
 	/* DMIC, MIC, Line-in*/
 	0x07, 0x08, 0x09
@@ -19686,8 +19657,7 @@ static void alc680_rec_autoswitch(struct hda_codec *codec)
 
 	for (i = 0; i < cfg->num_inputs; i++) {
 		nid = cfg->inputs[i].pin;
-		if (!(snd_hda_query_pin_caps(codec, nid) &
-		      AC_PINCAP_PRES_DETECT))
+		if (!is_jack_detectable(codec, nid))
 			continue;
 		if (snd_hda_jack_detect(codec, nid)) {
 			if (cfg->inputs[i].type < type_found) {
@@ -19734,7 +19704,7 @@ static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 	return 0;
 }
 
-static struct hda_pcm_stream alc680_pcm_analog_auto_capture = {
+static const struct hda_pcm_stream alc680_pcm_analog_auto_capture = {
 	.substreams = 1, /* can be overridden */
 	.channels_min = 2,
 	.channels_max = 2,
@@ -19745,7 +19715,7 @@ static struct hda_pcm_stream alc680_pcm_analog_auto_capture = {
 	},
 };
 
-static struct snd_kcontrol_new alc680_base_mixer[] = {
+static const struct snd_kcontrol_new alc680_base_mixer[] = {
 	/* output mixer control */
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -19757,7 +19727,7 @@ static struct snd_kcontrol_new alc680_base_mixer[] = {
 	{ }
 };
 
-static struct hda_bind_ctls alc680_bind_cap_vol = {
+static const struct hda_bind_ctls alc680_bind_cap_vol = {
 	.ops = &snd_hda_bind_vol,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
@@ -19767,7 +19737,7 @@ static struct hda_bind_ctls alc680_bind_cap_vol = {
 	},
 };
 
-static struct hda_bind_ctls alc680_bind_cap_switch = {
+static const struct hda_bind_ctls alc680_bind_cap_switch = {
 	.ops = &snd_hda_bind_sw,
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
@@ -19777,7 +19747,7 @@ static struct hda_bind_ctls alc680_bind_cap_switch = {
 	},
 };
 
-static struct snd_kcontrol_new alc680_master_capture_mixer[] = {
+static const struct snd_kcontrol_new alc680_master_capture_mixer[] = {
 	HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol),
 	HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch),
 	{ } /* end */
@@ -19786,7 +19756,7 @@ static struct snd_kcontrol_new alc680_master_capture_mixer[] = {
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
-static struct hda_verb alc680_init_verbs[] = {
+static const struct hda_verb alc680_init_verbs[] = {
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -19824,20 +19794,22 @@ static void alc680_base_setup(struct hda_codec *codec)
 	spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
 	spec->autocfg.inputs[1].pin = 0x19;
 	spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 
 static void alc680_unsol_event(struct hda_codec *codec,
 					   unsigned int res)
 {
 	if ((res >> 26) == ALC880_HP_EVENT)
-		alc_automute_amp(codec);
+		alc_hp_automute(codec);
 	if ((res >> 26) == ALC880_MIC_EVENT)
 		alc680_rec_autoswitch(codec);
 }
 
 static void alc680_inithook(struct hda_codec *codec)
 {
-	alc_automute_amp(codec);
+	alc_hp_automute(codec);
 	alc680_rec_autoswitch(codec);
 }
 
@@ -19874,7 +19846,7 @@ static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
 
 		if (err < 0)
 			return err;
-		spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
+		spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
 	}
 
 	return 0;
@@ -19960,7 +19932,7 @@ static int alc680_parse_auto_config(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 	int err;
-	static hda_nid_t alc680_ignore[] = { 0 };
+	static const hda_nid_t alc680_ignore[] = { 0 };
 
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 					   alc680_ignore);
@@ -20018,12 +19990,12 @@ static const char * const alc680_models[ALC680_MODEL_LAST] = {
 	[ALC680_AUTO]		= "auto",
 };
 
-static struct snd_pci_quirk alc680_cfg_tbl[] = {
+static const struct snd_pci_quirk alc680_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
 	{}
 };
 
-static struct alc_config_preset alc680_presets[] = {
+static const struct alc_config_preset alc680_presets[] = {
 	[ALC680_BASE] = {
 		.mixers = { alc680_base_mixer },
 		.cap_mixer =  alc680_master_capture_mixer,
@@ -20104,7 +20076,8 @@ static int patch_alc680(struct hda_codec *codec)
 /*
  * patch entries
  */
-static struct hda_codec_preset snd_hda_preset_realtek[] = {
+static const struct hda_codec_preset snd_hda_preset_realtek[] = {
+	{ .id = 0x10ec0221, .name = "ALC221", .patch = patch_alc269 },
 	{ .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
 	{ .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
 	{ .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
@@ -20113,6 +20086,7 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = {
 	{ .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
 	{ .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
 	{ .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
+	{ .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 },
 	{ .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
 	  .patch = patch_alc861 },
 	{ .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
@@ -20140,6 +20114,7 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = {
 	{ .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
 	{ .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
 	{ .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
+	{ .id = 0x10ec0899, .name = "ALC899", .patch = patch_alc899 },
 	{} /* terminator */
 };
 
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
index f419ee8d75f0..2f55f32876fa 100644
--- a/sound/pci/hda/patch_si3054.c
+++ b/sound/pci/hda/patch_si3054.c
@@ -130,7 +130,7 @@ static int si3054_switch_put(struct snd_kcontrol *kcontrol,
 }
 		
 
-static struct snd_kcontrol_new si3054_modem_mixer[] = {
+static const struct snd_kcontrol_new si3054_modem_mixer[] = {
 	SI3054_KCONTROL("Off-hook Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_OH),
 	SI3054_KCONTROL("Caller ID Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_CID),
 	{}
@@ -181,7 +181,7 @@ static int si3054_pcm_open(struct hda_pcm_stream *hinfo,
 }
 
 
-static struct hda_pcm_stream si3054_pcm = {
+static const struct hda_pcm_stream si3054_pcm = {
 	.substreams = 1,
 	.channels_min = 1,
 	.channels_max = 1,
@@ -200,12 +200,13 @@ static int si3054_build_pcms(struct hda_codec *codec)
 {
 	struct si3054_spec *spec = codec->spec;
 	struct hda_pcm *info = &spec->pcm;
-	si3054_pcm.nid = codec->mfg;
 	codec->num_pcms = 1;
 	codec->pcm_info = info;
 	info->name = "Si3054 Modem";
 	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = si3054_pcm;
 	info->stream[SNDRV_PCM_STREAM_CAPTURE]  = si3054_pcm;
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = codec->mfg;
+	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = codec->mfg;
 	info->pcm_type = HDA_PCM_TYPE_MODEM;
 	return 0;
 }
@@ -263,7 +264,7 @@ static void si3054_free(struct hda_codec *codec)
 /*
  */
 
-static struct hda_codec_ops si3054_patch_ops = {
+static const struct hda_codec_ops si3054_patch_ops = {
 	.build_controls = si3054_build_controls,
 	.build_pcms = si3054_build_pcms,
 	.init = si3054_init,
@@ -283,7 +284,7 @@ static int patch_si3054(struct hda_codec *codec)
 /*
  * patch entries
  */
-static struct hda_codec_preset snd_hda_preset_si3054[] = {
+static const struct hda_codec_preset snd_hda_preset_si3054[] = {
  	{ .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 },
  	{ .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 },
  	{ .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 },
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 94d19c03a7f4..7f81cc2274f3 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -217,15 +217,15 @@ struct sigmatel_spec {
 	unsigned int stream_delay;
 
 	/* analog loopback */
-	struct snd_kcontrol_new *aloopback_ctl;
+	const struct snd_kcontrol_new *aloopback_ctl;
 	unsigned char aloopback_mask;
 	unsigned char aloopback_shift;
 
 	/* power management */
 	unsigned int num_pwrs;
-	unsigned int *pwr_mapping;
-	hda_nid_t *pwr_nids;
-	hda_nid_t *dac_list;
+	const unsigned int *pwr_mapping;
+	const hda_nid_t *pwr_nids;
+	const hda_nid_t *dac_list;
 
 	/* events */
 	struct snd_array events;
@@ -241,20 +241,20 @@ struct sigmatel_spec {
 	int volume_offset;
 
 	/* capture */
-	hda_nid_t *adc_nids;
+	const hda_nid_t *adc_nids;
 	unsigned int num_adcs;
-	hda_nid_t *mux_nids;
+	const hda_nid_t *mux_nids;
 	unsigned int num_muxes;
-	hda_nid_t *dmic_nids;
+	const hda_nid_t *dmic_nids;
 	unsigned int num_dmics;
-	hda_nid_t *dmux_nids;
+	const hda_nid_t *dmux_nids;
 	unsigned int num_dmuxes;
-	hda_nid_t *smux_nids;
+	const hda_nid_t *smux_nids;
 	unsigned int num_smuxes;
 	unsigned int num_analog_muxes;
 
-	unsigned long *capvols; /* amp-volume attr: HDA_COMPOSE_AMP_VAL() */
-	unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */
+	const unsigned long *capvols; /* amp-volume attr: HDA_COMPOSE_AMP_VAL() */
+	const unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */
 	unsigned int num_caps; /* number of capture volume/switch elements */
 
 	struct sigmatel_mic_route ext_mic;
@@ -269,12 +269,12 @@ struct sigmatel_spec {
 	hda_nid_t digbeep_nid;
 
 	/* pin widgets */
-	hda_nid_t *pin_nids;
+	const hda_nid_t *pin_nids;
 	unsigned int num_pins;
 
 	/* codec specific stuff */
-	struct hda_verb *init;
-	struct snd_kcontrol_new *mixer;
+	const struct hda_verb *init;
+	const struct snd_kcontrol_new *mixer;
 
 	/* capture source */
 	struct hda_input_mux *dinput_mux;
@@ -317,52 +317,52 @@ struct sigmatel_spec {
 	hda_nid_t auto_dmic_nids[MAX_DMICS_NUM];
 };
 
-static hda_nid_t stac9200_adc_nids[1] = {
+static const hda_nid_t stac9200_adc_nids[1] = {
         0x03,
 };
 
-static hda_nid_t stac9200_mux_nids[1] = {
+static const hda_nid_t stac9200_mux_nids[1] = {
         0x0c,
 };
 
-static hda_nid_t stac9200_dac_nids[1] = {
+static const hda_nid_t stac9200_dac_nids[1] = {
         0x02,
 };
 
-static hda_nid_t stac92hd73xx_pwr_nids[8] = {
+static const hda_nid_t stac92hd73xx_pwr_nids[8] = {
 	0x0a, 0x0b, 0x0c, 0xd, 0x0e,
 	0x0f, 0x10, 0x11
 };
 
-static hda_nid_t stac92hd73xx_slave_dig_outs[2] = {
+static const hda_nid_t stac92hd73xx_slave_dig_outs[2] = {
 	0x26, 0,
 };
 
-static hda_nid_t stac92hd73xx_adc_nids[2] = {
+static const hda_nid_t stac92hd73xx_adc_nids[2] = {
 	0x1a, 0x1b
 };
 
 #define STAC92HD73XX_NUM_DMICS	2
-static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
+static const hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
 	0x13, 0x14, 0
 };
 
 #define STAC92HD73_DAC_COUNT 5
 
-static hda_nid_t stac92hd73xx_mux_nids[2] = {
+static const hda_nid_t stac92hd73xx_mux_nids[2] = {
 	0x20, 0x21,
 };
 
-static hda_nid_t stac92hd73xx_dmux_nids[2] = {
+static const hda_nid_t stac92hd73xx_dmux_nids[2] = {
 	0x20, 0x21,
 };
 
-static hda_nid_t stac92hd73xx_smux_nids[2] = {
+static const hda_nid_t stac92hd73xx_smux_nids[2] = {
 	0x22, 0x23,
 };
 
 #define STAC92HD73XX_NUM_CAPS	2
-static unsigned long stac92hd73xx_capvols[] = {
+static const unsigned long stac92hd73xx_capvols[] = {
 	HDA_COMPOSE_AMP_VAL(0x20, 3, 0, HDA_OUTPUT),
 	HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
 };
@@ -370,137 +370,141 @@ static unsigned long stac92hd73xx_capvols[] = {
 
 #define STAC92HD83_DAC_COUNT 3
 
-static hda_nid_t stac92hd83xxx_pwr_nids[4] = {
+static const hda_nid_t stac92hd83xxx_pwr_nids[4] = {
 	0xa, 0xb, 0xd, 0xe,
 };
 
-static hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
+static const hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
 	0x1e, 0,
 };
 
-static unsigned int stac92hd83xxx_pwr_mapping[4] = {
+static const unsigned int stac92hd83xxx_pwr_mapping[4] = {
 	0x03, 0x0c, 0x20, 0x40,
 };
 
-static hda_nid_t stac92hd83xxx_dmic_nids[] = {
+static const hda_nid_t stac92hd83xxx_dmic_nids[] = {
 		0x11, 0x20,
 };
 
-static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
+static const hda_nid_t stac92hd71bxx_pwr_nids[3] = {
 	0x0a, 0x0d, 0x0f
 };
 
-static hda_nid_t stac92hd71bxx_adc_nids[2] = {
+static const hda_nid_t stac92hd71bxx_adc_nids[2] = {
 	0x12, 0x13,
 };
 
-static hda_nid_t stac92hd71bxx_mux_nids[2] = {
+static const hda_nid_t stac92hd71bxx_mux_nids[2] = {
 	0x1a, 0x1b
 };
 
-static hda_nid_t stac92hd71bxx_dmux_nids[2] = {
+static const hda_nid_t stac92hd71bxx_dmux_nids[2] = {
 	0x1c, 0x1d,
 };
 
-static hda_nid_t stac92hd71bxx_smux_nids[2] = {
+static const hda_nid_t stac92hd71bxx_smux_nids[2] = {
 	0x24, 0x25,
 };
 
 #define STAC92HD71BXX_NUM_DMICS	2
-static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
+static const hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
 	0x18, 0x19, 0
 };
 
-static hda_nid_t stac92hd71bxx_slave_dig_outs[2] = {
+static const hda_nid_t stac92hd71bxx_dmic_5port_nids[STAC92HD71BXX_NUM_DMICS] = {
+	0x18, 0
+};
+
+static const hda_nid_t stac92hd71bxx_slave_dig_outs[2] = {
 	0x22, 0
 };
 
 #define STAC92HD71BXX_NUM_CAPS		2
-static unsigned long stac92hd71bxx_capvols[] = {
+static const unsigned long stac92hd71bxx_capvols[] = {
 	HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT),
 	HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
 };
 #define stac92hd71bxx_capsws	stac92hd71bxx_capvols
 
-static hda_nid_t stac925x_adc_nids[1] = {
+static const hda_nid_t stac925x_adc_nids[1] = {
         0x03,
 };
 
-static hda_nid_t stac925x_mux_nids[1] = {
+static const hda_nid_t stac925x_mux_nids[1] = {
         0x0f,
 };
 
-static hda_nid_t stac925x_dac_nids[1] = {
+static const hda_nid_t stac925x_dac_nids[1] = {
         0x02,
 };
 
 #define STAC925X_NUM_DMICS	1
-static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
+static const hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
 	0x15, 0
 };
 
-static hda_nid_t stac925x_dmux_nids[1] = {
+static const hda_nid_t stac925x_dmux_nids[1] = {
 	0x14,
 };
 
-static unsigned long stac925x_capvols[] = {
+static const unsigned long stac925x_capvols[] = {
 	HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
 };
-static unsigned long stac925x_capsws[] = {
+static const unsigned long stac925x_capsws[] = {
 	HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
 };
 
-static hda_nid_t stac922x_adc_nids[2] = {
+static const hda_nid_t stac922x_adc_nids[2] = {
         0x06, 0x07,
 };
 
-static hda_nid_t stac922x_mux_nids[2] = {
+static const hda_nid_t stac922x_mux_nids[2] = {
         0x12, 0x13,
 };
 
 #define STAC922X_NUM_CAPS	2
-static unsigned long stac922x_capvols[] = {
+static const unsigned long stac922x_capvols[] = {
 	HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT),
 	HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT),
 };
 #define stac922x_capsws		stac922x_capvols
 
-static hda_nid_t stac927x_slave_dig_outs[2] = {
+static const hda_nid_t stac927x_slave_dig_outs[2] = {
 	0x1f, 0,
 };
 
-static hda_nid_t stac927x_adc_nids[3] = {
+static const hda_nid_t stac927x_adc_nids[3] = {
         0x07, 0x08, 0x09
 };
 
-static hda_nid_t stac927x_mux_nids[3] = {
+static const hda_nid_t stac927x_mux_nids[3] = {
         0x15, 0x16, 0x17
 };
 
-static hda_nid_t stac927x_smux_nids[1] = {
+static const hda_nid_t stac927x_smux_nids[1] = {
 	0x21,
 };
 
-static hda_nid_t stac927x_dac_nids[6] = {
+static const hda_nid_t stac927x_dac_nids[6] = {
 	0x02, 0x03, 0x04, 0x05, 0x06, 0
 };
 
-static hda_nid_t stac927x_dmux_nids[1] = {
+static const hda_nid_t stac927x_dmux_nids[1] = {
 	0x1b,
 };
 
 #define STAC927X_NUM_DMICS 2
-static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
+static const hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
 	0x13, 0x14, 0
 };
 
 #define STAC927X_NUM_CAPS	3
-static unsigned long stac927x_capvols[] = {
+static const unsigned long stac927x_capvols[] = {
 	HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT),
 	HDA_COMPOSE_AMP_VAL(0x19, 3, 0, HDA_INPUT),
 	HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_INPUT),
 };
-static unsigned long stac927x_capsws[] = {
+static const unsigned long stac927x_capsws[] = {
 	HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
 	HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT),
 	HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
@@ -511,77 +515,77 @@ static const char * const stac927x_spdif_labels[5] = {
 	"Analog Mux 2", "Analog Mux 3"
 };
 
-static hda_nid_t stac9205_adc_nids[2] = {
+static const hda_nid_t stac9205_adc_nids[2] = {
         0x12, 0x13
 };
 
-static hda_nid_t stac9205_mux_nids[2] = {
+static const hda_nid_t stac9205_mux_nids[2] = {
         0x19, 0x1a
 };
 
-static hda_nid_t stac9205_dmux_nids[1] = {
+static const hda_nid_t stac9205_dmux_nids[1] = {
 	0x1d,
 };
 
-static hda_nid_t stac9205_smux_nids[1] = {
+static const hda_nid_t stac9205_smux_nids[1] = {
 	0x21,
 };
 
 #define STAC9205_NUM_DMICS	2
-static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
+static const hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
         0x17, 0x18, 0
 };
 
 #define STAC9205_NUM_CAPS	2
-static unsigned long stac9205_capvols[] = {
+static const unsigned long stac9205_capvols[] = {
 	HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_INPUT),
 	HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_INPUT),
 };
-static unsigned long stac9205_capsws[] = {
+static const unsigned long stac9205_capsws[] = {
 	HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
 	HDA_COMPOSE_AMP_VAL(0x1e, 3, 0, HDA_OUTPUT),
 };
 
-static hda_nid_t stac9200_pin_nids[8] = {
+static const hda_nid_t stac9200_pin_nids[8] = {
 	0x08, 0x09, 0x0d, 0x0e, 
 	0x0f, 0x10, 0x11, 0x12,
 };
 
-static hda_nid_t stac925x_pin_nids[8] = {
+static const hda_nid_t stac925x_pin_nids[8] = {
 	0x07, 0x08, 0x0a, 0x0b, 
 	0x0c, 0x0d, 0x10, 0x11,
 };
 
-static hda_nid_t stac922x_pin_nids[10] = {
+static const hda_nid_t stac922x_pin_nids[10] = {
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0f, 0x10, 0x11, 0x15, 0x1b,
 };
 
-static hda_nid_t stac92hd73xx_pin_nids[13] = {
+static const hda_nid_t stac92hd73xx_pin_nids[13] = {
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0f, 0x10, 0x11, 0x12, 0x13,
 	0x14, 0x22, 0x23
 };
 
 #define STAC92HD71BXX_NUM_PINS 13
-static hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = {
+static const hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = {
 	0x0a, 0x0b, 0x0c, 0x0d, 0x00,
 	0x00, 0x14, 0x18, 0x19, 0x1e,
 	0x1f, 0x20, 0x27
 };
-static hda_nid_t stac92hd71bxx_pin_nids_6port[STAC92HD71BXX_NUM_PINS] = {
+static const hda_nid_t stac92hd71bxx_pin_nids_6port[STAC92HD71BXX_NUM_PINS] = {
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0f, 0x14, 0x18, 0x19, 0x1e,
 	0x1f, 0x20, 0x27
 };
 
-static hda_nid_t stac927x_pin_nids[14] = {
+static const hda_nid_t stac927x_pin_nids[14] = {
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0f, 0x10, 0x11, 0x12, 0x13,
 	0x14, 0x21, 0x22, 0x23,
 };
 
-static hda_nid_t stac9205_pin_nids[12] = {
+static const hda_nid_t stac9205_pin_nids[12] = {
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0f, 0x14, 0x16, 0x17, 0x18,
 	0x21, 0x22,
@@ -841,45 +845,45 @@ static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
 	return 1;
 }
 
-static struct hda_verb stac9200_core_init[] = {
+static const struct hda_verb stac9200_core_init[] = {
 	/* set dac0mux for dac converter */
 	{ 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{}
 };
 
-static struct hda_verb stac9200_eapd_init[] = {
+static const struct hda_verb stac9200_eapd_init[] = {
 	/* set dac0mux for dac converter */
 	{0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
 	{}
 };
 
-static struct hda_verb dell_eq_core_init[] = {
+static const struct hda_verb dell_eq_core_init[] = {
 	/* set master volume to max value without distortion
 	 * and direct control */
 	{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
 	{}
 };
 
-static struct hda_verb stac92hd73xx_core_init[] = {
+static const struct hda_verb stac92hd73xx_core_init[] = {
 	/* set master volume and direct control */
 	{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	{}
 };
 
-static struct hda_verb stac92hd83xxx_core_init[] = {
+static const struct hda_verb stac92hd83xxx_core_init[] = {
 	/* power state controls amps */
 	{ 0x01, AC_VERB_SET_EAPD, 1 << 2},
 	{}
 };
 
-static struct hda_verb stac92hd71bxx_core_init[] = {
+static const struct hda_verb stac92hd71bxx_core_init[] = {
 	/* set master volume and direct control */
 	{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	{}
 };
 
-static struct hda_verb stac92hd71bxx_unmute_core_init[] = {
+static const struct hda_verb stac92hd71bxx_unmute_core_init[] = {
 	/* unmute right and left channels for nodes 0x0f, 0xa, 0x0d */
 	{ 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -887,7 +891,7 @@ static struct hda_verb stac92hd71bxx_unmute_core_init[] = {
 	{}
 };
 
-static struct hda_verb stac925x_core_init[] = {
+static const struct hda_verb stac925x_core_init[] = {
 	/* set dac0mux for dac converter */
 	{ 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
 	/* mute the master volume */
@@ -895,13 +899,13 @@ static struct hda_verb stac925x_core_init[] = {
 	{}
 };
 
-static struct hda_verb stac922x_core_init[] = {
+static const struct hda_verb stac922x_core_init[] = {
 	/* set master volume and direct control */	
 	{ 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	{}
 };
 
-static struct hda_verb d965_core_init[] = {
+static const struct hda_verb d965_core_init[] = {
 	/* set master volume and direct control */	
 	{ 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	/* unmute node 0x1b */
@@ -911,7 +915,7 @@ static struct hda_verb d965_core_init[] = {
 	{}
 };
 
-static struct hda_verb dell_3st_core_init[] = {
+static const struct hda_verb dell_3st_core_init[] = {
 	/* don't set delta bit */
 	{0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f},
 	/* unmute node 0x1b */
@@ -921,7 +925,7 @@ static struct hda_verb dell_3st_core_init[] = {
 	{}
 };
 
-static struct hda_verb stac927x_core_init[] = {
+static const struct hda_verb stac927x_core_init[] = {
 	/* set master volume and direct control */	
 	{ 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	/* enable analog pc beep path */
@@ -929,7 +933,7 @@ static struct hda_verb stac927x_core_init[] = {
 	{}
 };
 
-static struct hda_verb stac927x_volknob_core_init[] = {
+static const struct hda_verb stac927x_volknob_core_init[] = {
 	/* don't set delta bit */
 	{0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f},
 	/* enable analog pc beep path */
@@ -937,7 +941,7 @@ static struct hda_verb stac927x_volknob_core_init[] = {
 	{}
 };
 
-static struct hda_verb stac9205_core_init[] = {
+static const struct hda_verb stac9205_core_init[] = {
 	/* set master volume and direct control */	
 	{ 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	/* enable analog pc beep path */
@@ -977,7 +981,7 @@ static struct hda_verb stac9205_core_init[] = {
 		.private_value = nid, \
 	}
 
-static struct snd_kcontrol_new stac9200_mixer[] = {
+static const struct snd_kcontrol_new stac9200_mixer[] = {
 	HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
@@ -985,38 +989,38 @@ static struct snd_kcontrol_new stac9200_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new stac92hd73xx_6ch_loopback[] = {
+static const struct snd_kcontrol_new stac92hd73xx_6ch_loopback[] = {
 	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
 	{}
 };
 
-static struct snd_kcontrol_new stac92hd73xx_8ch_loopback[] = {
+static const struct snd_kcontrol_new stac92hd73xx_8ch_loopback[] = {
 	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
 	{}
 };
 
-static struct snd_kcontrol_new stac92hd73xx_10ch_loopback[] = {
+static const struct snd_kcontrol_new stac92hd73xx_10ch_loopback[] = {
 	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
 	{}
 };
 
 
-static struct snd_kcontrol_new stac92hd71bxx_loopback[] = {
+static const struct snd_kcontrol_new stac92hd71bxx_loopback[] = {
 	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2)
 };
 
-static struct snd_kcontrol_new stac925x_mixer[] = {
+static const struct snd_kcontrol_new stac925x_mixer[] = {
 	HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xe, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT),
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new stac9205_loopback[] = {
+static const struct snd_kcontrol_new stac9205_loopback[] = {
 	STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
 	{}
 };
 
-static struct snd_kcontrol_new stac927x_loopback[] = {
+static const struct snd_kcontrol_new stac927x_loopback[] = {
 	STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
 	{}
 };
@@ -1182,16 +1186,16 @@ static int stac92xx_build_controls(struct hda_codec *codec)
 	return 0;	
 }
 
-static unsigned int ref9200_pin_configs[8] = {
+static const unsigned int ref9200_pin_configs[8] = {
 	0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
 	0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
 };
 
-static unsigned int gateway9200_m4_pin_configs[8] = {
+static const unsigned int gateway9200_m4_pin_configs[8] = {
 	0x400000fe, 0x404500f4, 0x400100f0, 0x90110010,
 	0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3,
 };
-static unsigned int gateway9200_m4_2_pin_configs[8] = {
+static const unsigned int gateway9200_m4_2_pin_configs[8] = {
 	0x400000fe, 0x404500f4, 0x400100f0, 0x90110010,
 	0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3,
 };
@@ -1202,7 +1206,7 @@ static unsigned int gateway9200_m4_2_pin_configs[8] = {
     102801DE
     102801E8
 */
-static unsigned int dell9200_d21_pin_configs[8] = {
+static const unsigned int dell9200_d21_pin_configs[8] = {
 	0x400001f0, 0x400001f1, 0x02214030, 0x01014010, 
 	0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
 };
@@ -1212,7 +1216,7 @@ static unsigned int dell9200_d21_pin_configs[8] = {
     102801C0
     102801C1
 */
-static unsigned int dell9200_d22_pin_configs[8] = {
+static const unsigned int dell9200_d22_pin_configs[8] = {
 	0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, 
 	0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
 };
@@ -1226,7 +1230,7 @@ static unsigned int dell9200_d22_pin_configs[8] = {
     102801DA
     102801E3
 */
-static unsigned int dell9200_d23_pin_configs[8] = {
+static const unsigned int dell9200_d23_pin_configs[8] = {
 	0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, 
 	0x01813020, 0x01a19021, 0x90100140, 0x400001f2, 
 };
@@ -1237,7 +1241,7 @@ static unsigned int dell9200_d23_pin_configs[8] = {
     102801B5 (Dell Inspiron 630m)
     102801D8 (Dell Inspiron 640m)
 */
-static unsigned int dell9200_m21_pin_configs[8] = {
+static const unsigned int dell9200_m21_pin_configs[8] = {
 	0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
 	0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
 };
@@ -1250,7 +1254,7 @@ static unsigned int dell9200_m21_pin_configs[8] = {
     102801D4 
     102801D6 
 */
-static unsigned int dell9200_m22_pin_configs[8] = {
+static const unsigned int dell9200_m22_pin_configs[8] = {
 	0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310, 
 	0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
 };
@@ -1260,7 +1264,7 @@ static unsigned int dell9200_m22_pin_configs[8] = {
     102801CE (Dell XPS M1710)
     102801CF (Dell Precision M90)
 */
-static unsigned int dell9200_m23_pin_configs[8] = {
+static const unsigned int dell9200_m23_pin_configs[8] = {
 	0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
 	0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
 };
@@ -1272,7 +1276,7 @@ static unsigned int dell9200_m23_pin_configs[8] = {
     102801CB (Dell Latitude 120L)
     102801D3
 */
-static unsigned int dell9200_m24_pin_configs[8] = {
+static const unsigned int dell9200_m24_pin_configs[8] = {
 	0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310, 
 	0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe, 
 };
@@ -1283,7 +1287,7 @@ static unsigned int dell9200_m24_pin_configs[8] = {
     102801EE
     102801EF
 */
-static unsigned int dell9200_m25_pin_configs[8] = {
+static const unsigned int dell9200_m25_pin_configs[8] = {
 	0x40c003fa, 0x01441340, 0x0421121f, 0x90170310, 
 	0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
 };
@@ -1293,7 +1297,7 @@ static unsigned int dell9200_m25_pin_configs[8] = {
     102801F5 (Dell Inspiron 1501)
     102801F6
 */
-static unsigned int dell9200_m26_pin_configs[8] = {
+static const unsigned int dell9200_m26_pin_configs[8] = {
 	0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310, 
 	0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
 };
@@ -1302,18 +1306,18 @@ static unsigned int dell9200_m26_pin_configs[8] = {
     STAC 9200-32
     102801CD (Dell Inspiron E1705/9400)
 */
-static unsigned int dell9200_m27_pin_configs[8] = {
+static const unsigned int dell9200_m27_pin_configs[8] = {
 	0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
 	0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
 };
 
-static unsigned int oqo9200_pin_configs[8] = {
+static const unsigned int oqo9200_pin_configs[8] = {
 	0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
 	0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
 };
 
 
-static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
+static const unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
 	[STAC_REF] = ref9200_pin_configs,
 	[STAC_9200_OQO] = oqo9200_pin_configs,
 	[STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
@@ -1350,7 +1354,7 @@ static const char * const stac9200_models[STAC_9200_MODELS] = {
 	[STAC_9200_PANASONIC] = "panasonic",
 };
 
-static struct snd_pci_quirk stac9200_cfg_tbl[] = {
+static const struct snd_pci_quirk stac9200_cfg_tbl[] = {
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 		      "DFI LanParty", STAC_REF),
@@ -1426,47 +1430,47 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = {
 	{} /* terminator */
 };
 
-static unsigned int ref925x_pin_configs[8] = {
+static const unsigned int ref925x_pin_configs[8] = {
 	0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
 	0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
 };
 
-static unsigned int stac925xM1_pin_configs[8] = {
+static const unsigned int stac925xM1_pin_configs[8] = {
 	0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
 	0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
 };
 
-static unsigned int stac925xM1_2_pin_configs[8] = {
+static const unsigned int stac925xM1_2_pin_configs[8] = {
 	0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
 	0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
 };
 
-static unsigned int stac925xM2_pin_configs[8] = {
+static const unsigned int stac925xM2_pin_configs[8] = {
 	0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
 	0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
 };
 
-static unsigned int stac925xM2_2_pin_configs[8] = {
+static const unsigned int stac925xM2_2_pin_configs[8] = {
 	0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
 	0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
 };
 
-static unsigned int stac925xM3_pin_configs[8] = {
+static const unsigned int stac925xM3_pin_configs[8] = {
 	0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
 	0x40a000f0, 0x90100210, 0x400003f1, 0x503303f3,
 };
 
-static unsigned int stac925xM5_pin_configs[8] = {
+static const unsigned int stac925xM5_pin_configs[8] = {
 	0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
 	0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
 };
 
-static unsigned int stac925xM6_pin_configs[8] = {
+static const unsigned int stac925xM6_pin_configs[8] = {
 	0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
 	0x40a000f0, 0x90100210, 0x400003f1, 0x90330320,
 };
 
-static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
+static const unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
 	[STAC_REF] = ref925x_pin_configs,
 	[STAC_M1] = stac925xM1_pin_configs,
 	[STAC_M1_2] = stac925xM1_2_pin_configs,
@@ -1489,7 +1493,7 @@ static const char * const stac925x_models[STAC_925x_MODELS] = {
 	[STAC_M6] = "m6",
 };
 
-static struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = {
+static const struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_M2),
 	SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_M5),
 	SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_M1),
@@ -1503,7 +1507,7 @@ static struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = {
 	{} /* terminator */
 };
 
-static struct snd_pci_quirk stac925x_cfg_tbl[] = {
+static const struct snd_pci_quirk stac925x_cfg_tbl[] = {
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF),
@@ -1515,33 +1519,33 @@ static struct snd_pci_quirk stac925x_cfg_tbl[] = {
 	{} /* terminator */
 };
 
-static unsigned int ref92hd73xx_pin_configs[13] = {
+static const unsigned int ref92hd73xx_pin_configs[13] = {
 	0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
 	0x0181302e, 0x01014010, 0x01014020, 0x01014030,
 	0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
 	0x01452050,
 };
 
-static unsigned int dell_m6_pin_configs[13] = {
+static const unsigned int dell_m6_pin_configs[13] = {
 	0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
 	0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0,
 	0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
 	0x4f0000f0,
 };
 
-static unsigned int alienware_m17x_pin_configs[13] = {
+static const unsigned int alienware_m17x_pin_configs[13] = {
 	0x0321101f, 0x0321101f, 0x03a11020, 0x03014020,
 	0x90170110, 0x4f0000f0, 0x4f0000f0, 0x4f0000f0,
 	0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
 	0x904601b0,
 };
 
-static unsigned int intel_dg45id_pin_configs[13] = {
+static const unsigned int intel_dg45id_pin_configs[13] = {
 	0x02214230, 0x02A19240, 0x01013214, 0x01014210,
 	0x01A19250, 0x01011212, 0x01016211
 };
 
-static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
+static const unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
 	[STAC_92HD73XX_REF]	= ref92hd73xx_pin_configs,
 	[STAC_DELL_M6_AMIC]	= dell_m6_pin_configs,
 	[STAC_DELL_M6_DMIC]	= dell_m6_pin_configs,
@@ -1563,7 +1567,7 @@ static const char * const stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
 	[STAC_ALIENWARE_M17X] = "alienware",
 };
 
-static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
+static const struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 				"DFI LanParty", STAC_92HD73XX_REF),
@@ -1600,11 +1604,11 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02fe,
 				"Dell Studio XPS 1645", STAC_DELL_M6_BOTH),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0413,
-				"Dell Studio 1558", STAC_DELL_M6_BOTH),
+				"Dell Studio 1558", STAC_DELL_M6_DMIC),
 	{} /* terminator */
 };
 
-static struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = {
+static const struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = {
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a1,
 		      "Alienware M17x", STAC_ALIENWARE_M17X),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x043a,
@@ -1612,25 +1616,25 @@ static struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = {
 	{} /* terminator */
 };
 
-static unsigned int ref92hd83xxx_pin_configs[10] = {
+static const unsigned int ref92hd83xxx_pin_configs[10] = {
 	0x02214030, 0x02211010, 0x02a19020, 0x02170130,
 	0x01014050, 0x01819040, 0x01014020, 0x90a3014e,
 	0x01451160, 0x98560170,
 };
 
-static unsigned int dell_s14_pin_configs[10] = {
+static const unsigned int dell_s14_pin_configs[10] = {
 	0x0221403f, 0x0221101f, 0x02a19020, 0x90170110,
 	0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a60160,
 	0x40f000f0, 0x40f000f0,
 };
 
-static unsigned int hp_dv7_4000_pin_configs[10] = {
+static const unsigned int hp_dv7_4000_pin_configs[10] = {
 	0x03a12050, 0x0321201f, 0x40f000f0, 0x90170110,
 	0x40f000f0, 0x40f000f0, 0x90170110, 0xd5a30140,
 	0x40f000f0, 0x40f000f0,
 };
 
-static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
+static const unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
 	[STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
 	[STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs,
 	[STAC_DELL_S14] = dell_s14_pin_configs,
@@ -1646,7 +1650,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
 	[STAC_HP_DV7_4000] = "hp-dv7-4000",
 };
 
-static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
+static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 		      "DFI LanParty", STAC_92HD83XXX_REF),
@@ -1659,35 +1663,35 @@ static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
 	{} /* terminator */
 };
 
-static unsigned int ref92hd71bxx_pin_configs[STAC92HD71BXX_NUM_PINS] = {
+static const unsigned int ref92hd71bxx_pin_configs[STAC92HD71BXX_NUM_PINS] = {
 	0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
 	0x0181302e, 0x01014010, 0x01019020, 0x90a000f0,
 	0x90a000f0, 0x01452050, 0x01452050, 0x00000000,
 	0x00000000
 };
 
-static unsigned int dell_m4_1_pin_configs[STAC92HD71BXX_NUM_PINS] = {
+static const unsigned int dell_m4_1_pin_configs[STAC92HD71BXX_NUM_PINS] = {
 	0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
 	0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
 	0x40f000f0, 0x4f0000f0, 0x4f0000f0, 0x00000000,
 	0x00000000
 };
 
-static unsigned int dell_m4_2_pin_configs[STAC92HD71BXX_NUM_PINS] = {
+static const unsigned int dell_m4_2_pin_configs[STAC92HD71BXX_NUM_PINS] = {
 	0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
 	0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
 	0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000,
 	0x00000000
 };
 
-static unsigned int dell_m4_3_pin_configs[STAC92HD71BXX_NUM_PINS] = {
+static const unsigned int dell_m4_3_pin_configs[STAC92HD71BXX_NUM_PINS] = {
 	0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
 	0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a000f0,
 	0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000,
 	0x00000000
 };
 
-static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
+static const unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
 	[STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
 	[STAC_DELL_M4_1]	= dell_m4_1_pin_configs,
 	[STAC_DELL_M4_2]	= dell_m4_2_pin_configs,
@@ -1712,7 +1716,7 @@ static const char * const stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
 	[STAC_HP_DV4_1222NR] = "hp-dv4-1222nr",
 };
 
-static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
+static const struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 		      "DFI LanParty", STAC_92HD71BXX_REF),
@@ -1769,7 +1773,7 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
 	{} /* terminator */
 };
 
-static unsigned int ref922x_pin_configs[10] = {
+static const unsigned int ref922x_pin_configs[10] = {
 	0x01014010, 0x01016011, 0x01012012, 0x0221401f,
 	0x01813122, 0x01011014, 0x01441030, 0x01c41030,
 	0x40000100, 0x40000100,
@@ -1783,7 +1787,7 @@ static unsigned int ref922x_pin_configs[10] = {
     102801D1
     102801D2
 */
-static unsigned int dell_922x_d81_pin_configs[10] = {
+static const unsigned int dell_922x_d81_pin_configs[10] = {
 	0x02214030, 0x01a19021, 0x01111012, 0x01114010,
 	0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
 	0x01813122, 0x400001f2,
@@ -1794,7 +1798,7 @@ static unsigned int dell_922x_d81_pin_configs[10] = {
     102801AC
     102801D0
 */
-static unsigned int dell_922x_d82_pin_configs[10] = {
+static const unsigned int dell_922x_d82_pin_configs[10] = {
 	0x02214030, 0x01a19021, 0x01111012, 0x01114010,
 	0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
 	0x01813122, 0x400001f1,
@@ -1804,7 +1808,7 @@ static unsigned int dell_922x_d82_pin_configs[10] = {
     STAC 922X pin configs for
     102801BF
 */
-static unsigned int dell_922x_m81_pin_configs[10] = {
+static const unsigned int dell_922x_m81_pin_configs[10] = {
 	0x0321101f, 0x01112024, 0x01111222, 0x91174220,
 	0x03a11050, 0x01116221, 0x90a70330, 0x01452340, 
 	0x40C003f1, 0x405003f0,
@@ -1814,61 +1818,61 @@ static unsigned int dell_922x_m81_pin_configs[10] = {
     STAC 9221 A1 pin configs for
     102801D7 (Dell XPS M1210)
 */
-static unsigned int dell_922x_m82_pin_configs[10] = {
+static const unsigned int dell_922x_m82_pin_configs[10] = {
 	0x02211211, 0x408103ff, 0x02a1123e, 0x90100310, 
 	0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2, 
 	0x508003f3, 0x405003f4, 
 };
 
-static unsigned int d945gtp3_pin_configs[10] = {
+static const unsigned int d945gtp3_pin_configs[10] = {
 	0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
 	0x40000100, 0x40000100, 0x40000100, 0x40000100,
 	0x02a19120, 0x40000100,
 };
 
-static unsigned int d945gtp5_pin_configs[10] = {
+static const unsigned int d945gtp5_pin_configs[10] = {
 	0x0221401f, 0x01011012, 0x01813024, 0x01014010,
 	0x01a19021, 0x01016011, 0x01452130, 0x40000100,
 	0x02a19320, 0x40000100,
 };
 
-static unsigned int intel_mac_v1_pin_configs[10] = {
+static const unsigned int intel_mac_v1_pin_configs[10] = {
 	0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
 	0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
 	0x400000fc, 0x400000fb,
 };
 
-static unsigned int intel_mac_v2_pin_configs[10] = {
+static const unsigned int intel_mac_v2_pin_configs[10] = {
 	0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
 	0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
 	0x400000fc, 0x400000fb,
 };
 
-static unsigned int intel_mac_v3_pin_configs[10] = {
+static const unsigned int intel_mac_v3_pin_configs[10] = {
 	0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
 	0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
 	0x400000fc, 0x400000fb,
 };
 
-static unsigned int intel_mac_v4_pin_configs[10] = {
+static const unsigned int intel_mac_v4_pin_configs[10] = {
 	0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
 	0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
 	0x400000fc, 0x400000fb,
 };
 
-static unsigned int intel_mac_v5_pin_configs[10] = {
+static const unsigned int intel_mac_v5_pin_configs[10] = {
 	0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
 	0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
 	0x400000fc, 0x400000fb,
 };
 
-static unsigned int ecs202_pin_configs[10] = {
+static const unsigned int ecs202_pin_configs[10] = {
 	0x0221401f, 0x02a19020, 0x01a19020, 0x01114010,
 	0x408000f0, 0x01813022, 0x074510a0, 0x40c400f1,
 	0x9037012e, 0x40e000f2,
 };
 
-static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
+static const unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
 	[STAC_D945_REF] = ref922x_pin_configs,
 	[STAC_D945GTP3] = d945gtp3_pin_configs,
 	[STAC_D945GTP5] = d945gtp5_pin_configs,
@@ -1917,7 +1921,7 @@ static const char * const stac922x_models[STAC_922X_MODELS] = {
 	[STAC_922X_DELL_M82] = "dell-m82",
 };
 
-static struct snd_pci_quirk stac922x_cfg_tbl[] = {
+static const struct snd_pci_quirk stac922x_cfg_tbl[] = {
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 		      "DFI LanParty", STAC_D945_REF),
@@ -2008,42 +2012,42 @@ static struct snd_pci_quirk stac922x_cfg_tbl[] = {
 	{} /* terminator */
 };
 
-static unsigned int ref927x_pin_configs[14] = {
+static const unsigned int ref927x_pin_configs[14] = {
 	0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
 	0x01a19040, 0x01011012, 0x01016011, 0x0101201f, 
 	0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
 	0x01c42190, 0x40000100,
 };
 
-static unsigned int d965_3st_pin_configs[14] = {
+static const unsigned int d965_3st_pin_configs[14] = {
 	0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
 	0x01a19021, 0x01813024, 0x40000100, 0x40000100,
 	0x40000100, 0x40000100, 0x40000100, 0x40000100,
 	0x40000100, 0x40000100
 };
 
-static unsigned int d965_5st_pin_configs[14] = {
+static const unsigned int d965_5st_pin_configs[14] = {
 	0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
 	0x01a19040, 0x01011012, 0x01016011, 0x40000100,
 	0x40000100, 0x40000100, 0x40000100, 0x01442070,
 	0x40000100, 0x40000100
 };
 
-static unsigned int d965_5st_no_fp_pin_configs[14] = {
+static const unsigned int d965_5st_no_fp_pin_configs[14] = {
 	0x40000100, 0x40000100, 0x0181304e, 0x01014010,
 	0x01a19040, 0x01011012, 0x01016011, 0x40000100,
 	0x40000100, 0x40000100, 0x40000100, 0x01442070,
 	0x40000100, 0x40000100
 };
 
-static unsigned int dell_3st_pin_configs[14] = {
+static const unsigned int dell_3st_pin_configs[14] = {
 	0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
 	0x01111212, 0x01116211, 0x01813050, 0x01112214,
 	0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
 	0x40c003fc, 0x40000100
 };
 
-static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
+static const unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
 	[STAC_D965_REF_NO_JD] = ref927x_pin_configs,
 	[STAC_D965_REF]  = ref927x_pin_configs,
 	[STAC_D965_3ST]  = d965_3st_pin_configs,
@@ -2066,7 +2070,7 @@ static const char * const stac927x_models[STAC_927X_MODELS] = {
 	[STAC_927X_VOLKNOB]	= "volknob",
 };
 
-static struct snd_pci_quirk stac927x_cfg_tbl[] = {
+static const struct snd_pci_quirk stac927x_cfg_tbl[] = {
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 		      "DFI LanParty", STAC_D965_REF),
@@ -2104,7 +2108,7 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = {
 	{} /* terminator */
 };
 
-static unsigned int ref9205_pin_configs[12] = {
+static const unsigned int ref9205_pin_configs[12] = {
 	0x40000100, 0x40000100, 0x01016011, 0x01014010,
 	0x01813122, 0x01a19021, 0x01019020, 0x40000100,
 	0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
@@ -2121,7 +2125,7 @@ static unsigned int ref9205_pin_configs[12] = {
     10280228 (Dell Vostro 1500)
     10280229 (Dell Vostro 1700)
 */
-static unsigned int dell_9205_m42_pin_configs[12] = {
+static const unsigned int dell_9205_m42_pin_configs[12] = {
 	0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
 	0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
 	0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
@@ -2137,19 +2141,19 @@ static unsigned int dell_9205_m42_pin_configs[12] = {
     10280200
     10280201
 */
-static unsigned int dell_9205_m43_pin_configs[12] = {
+static const unsigned int dell_9205_m43_pin_configs[12] = {
 	0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
 	0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
 	0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
 };
 
-static unsigned int dell_9205_m44_pin_configs[12] = {
+static const unsigned int dell_9205_m44_pin_configs[12] = {
 	0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
 	0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
 	0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
 };
 
-static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
+static const unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
 	[STAC_9205_REF] = ref9205_pin_configs,
 	[STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
 	[STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
@@ -2166,7 +2170,7 @@ static const char * const stac9205_models[STAC_9205_MODELS] = {
 	[STAC_9205_EAPD] = "eapd",
 };
 
-static struct snd_pci_quirk stac9205_cfg_tbl[] = {
+static const struct snd_pci_quirk stac9205_cfg_tbl[] = {
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 		      "DFI LanParty", STAC_9205_REF),
@@ -2214,7 +2218,7 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = {
 };
 
 static void stac92xx_set_config_regs(struct hda_codec *codec,
-				     unsigned int *pincfgs)
+				     const unsigned int *pincfgs)
 {
 	int i;
 	struct sigmatel_spec *spec = codec->spec;
@@ -2334,7 +2338,7 @@ static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 	return 0;
 }
 
-static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
+static const struct hda_pcm_stream stac92xx_pcm_digital_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -2347,14 +2351,14 @@ static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
 	},
 };
 
-static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
+static const struct hda_pcm_stream stac92xx_pcm_digital_capture = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
 	/* NID is set in stac92xx_build_pcms */
 };
 
-static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
+static const struct hda_pcm_stream stac92xx_pcm_analog_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 8,
@@ -2366,7 +2370,7 @@ static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
 	},
 };
 
-static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
+static const struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -2378,7 +2382,7 @@ static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
 	},
 };
 
-static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
+static const struct hda_pcm_stream stac92xx_pcm_analog_capture = {
 	.channels_min = 2,
 	.channels_max = 2,
 	/* NID + .substreams is set in stac92xx_build_pcms */
@@ -2487,7 +2491,7 @@ static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_info *uinfo)
 {
 	int i;
-	static char *texts[] = {
+	static const char * const texts[] = {
 		"Mic In", "Line In", "Line Out"
 	};
 
@@ -2556,7 +2560,7 @@ static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol,
 static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[2];
+	char *texts[2];
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct sigmatel_spec *spec = codec->spec;
 
@@ -2687,7 +2691,7 @@ enum {
 	STAC_CTL_WIDGET_DC_BIAS
 };
 
-static struct snd_kcontrol_new stac92xx_control_templates[] = {
+static const struct snd_kcontrol_new stac92xx_control_templates[] = {
 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
 	HDA_CODEC_MUTE(NULL, 0, 0, 0),
 	HDA_CODEC_MUTE_BEEP(NULL, 0, 0, 0),
@@ -2701,7 +2705,7 @@ static struct snd_kcontrol_new stac92xx_control_templates[] = {
 /* add dynamic controls */
 static struct snd_kcontrol_new *
 stac_control_new(struct sigmatel_spec *spec,
-		 struct snd_kcontrol_new *ktemp,
+		 const struct snd_kcontrol_new *ktemp,
 		 const char *name,
 		 unsigned int subdev)
 {
@@ -2724,7 +2728,7 @@ stac_control_new(struct sigmatel_spec *spec,
 }
 
 static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
-				     struct snd_kcontrol_new *ktemp,
+				     const struct snd_kcontrol_new *ktemp,
 				     int idx, const char *name,
 				     unsigned long val)
 {
@@ -2754,7 +2758,7 @@ static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type,
 	return stac92xx_add_control_idx(spec, type, 0, name, val);
 }
 
-static struct snd_kcontrol_new stac_input_src_temp = {
+static const struct snd_kcontrol_new stac_input_src_temp = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Input Source",
 	.info = stac92xx_mux_enum_info,
@@ -3072,7 +3076,8 @@ static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
 		printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
 		return 1;
 	} else {
-		spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
+		snd_BUG_ON(spec->multiout.dac_nids != spec->dac_nids);
+		spec->dac_nids[spec->multiout.num_dacs] = nid;
 		spec->multiout.num_dacs++;
 	}
 	return 0;
@@ -3109,8 +3114,7 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,
 
 	for (i = 0; i < num_outs && i < ARRAY_SIZE(chname); i++) {
 		if (type == AUTO_PIN_HP_OUT && !spec->hp_detect) {
-			wid_caps = get_wcaps(codec, pins[i]);
-			if (wid_caps & AC_WCAP_UNSOL_CAP)
+			if (is_jack_detectable(codec, pins[i]))
 				spec->hp_detect = 1;
 		}
 		nid = dac_nids[i];
@@ -3309,7 +3313,7 @@ static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol,
 	return snd_hda_enable_beep_device(codec, ucontrol->value.integer.value[0]);
 }
 
-static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = {
+static const struct snd_kcontrol_new stac92xx_dig_beep_ctrl = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.info = stac92xx_dig_beep_switch_info,
 	.get = stac92xx_dig_beep_switch_get,
@@ -3516,14 +3520,18 @@ static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid,
 			 hda_nid_t *fixed, hda_nid_t *ext, hda_nid_t *dock)
 {
 	unsigned int cfg;
+	unsigned int type;
 
 	if (!nid)
 		return 0;
 	cfg = snd_hda_codec_get_pincfg(codec, nid);
+	type = get_defcfg_device(cfg);
 	switch (snd_hda_get_input_pin_attr(cfg)) {
 	case INPUT_PIN_ATTR_INT:
 		if (*fixed)
 			return 1; /* already occupied */
+		if (type != AC_JACK_MIC_IN)
+			return 1; /* invalid type */
 		*fixed = nid;
 		break;
 	case INPUT_PIN_ATTR_UNUSED:
@@ -3531,11 +3539,15 @@ static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid,
 	case INPUT_PIN_ATTR_DOCK:
 		if (*dock)
 			return 1; /* already occupied */
+		if (type != AC_JACK_MIC_IN && type != AC_JACK_LINE_IN)
+			return 1; /* invalid type */
 		*dock = nid;
 		break;
 	default:
 		if (*ext)
 			return 1; /* already occupied */
+		if (type != AC_JACK_MIC_IN)
+			return 1; /* invalid type */
 		*ext = nid;
 		break;
 	}
@@ -3591,10 +3603,6 @@ static int stac_check_auto_mic(struct hda_codec *codec)
 	hda_nid_t fixed, ext, dock;
 	int i;
 
-	for (i = 0; i < cfg->num_inputs; i++) {
-		if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN)
-			return 0; /* must be exclusively mics */
-	}
 	fixed = ext = dock = 0;
 	for (i = 0; i < cfg->num_inputs; i++)
 		if (check_mic_pin(codec, cfg->inputs[i].pin,
@@ -3606,7 +3614,7 @@ static int stac_check_auto_mic(struct hda_codec *codec)
 			return 0;
 	if (!fixed || (!ext && !dock))
 		return 0; /* no input to switch */
-	if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
+	if (!is_jack_detectable(codec, ext))
 		return 0; /* no unsol support */
 	if (set_mic_route(codec, &spec->ext_mic, ext) ||
 	    set_mic_route(codec, &spec->int_mic, fixed) ||
@@ -3921,13 +3929,11 @@ static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
 {
 	struct sigmatel_spec *spec = codec->spec;
 	hda_nid_t pin = cfg->hp_pins[0];
-	unsigned int wid_caps;
 
 	if (! pin)
 		return 0;
 
-	wid_caps = get_wcaps(codec, pin);
-	if (wid_caps & AC_WCAP_UNSOL_CAP)
+	if (is_jack_detectable(codec, pin))
 		spec->hp_detect = 1;
 
 	return 0;
@@ -4138,7 +4144,7 @@ static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
 	struct sigmatel_event *event;
 	int tag;
 
-	if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
+	if (!is_jack_detectable(codec, nid))
 		return 0;
 	event = stac_get_event(codec, nid);
 	if (event) {
@@ -4171,7 +4177,7 @@ static void stac92xx_power_down(struct hda_codec *codec)
 	struct sigmatel_spec *spec = codec->spec;
 
 	/* power down inactive DACs */
-	hda_nid_t *dac;
+	const hda_nid_t *dac;
 	for (dac = spec->dac_list; *dac; dac++)
 		if (!check_all_dac_nids(spec, *dac))
 			snd_hda_codec_write(codec, *dac, 0,
@@ -4644,7 +4650,7 @@ static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
 }
 
 static int stac92xx_connected_ports(struct hda_codec *codec,
-					 hda_nid_t *nids, int num_nids)
+				    const hda_nid_t *nids, int num_nids)
 {
 	struct sigmatel_spec *spec = codec->spec;
 	int idx, num;
@@ -4968,7 +4974,7 @@ static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
 }
 #endif
 
-static struct hda_codec_ops stac92xx_patch_ops = {
+static const struct hda_codec_ops stac92xx_patch_ops = {
 	.build_controls = stac92xx_build_controls,
 	.build_pcms = stac92xx_build_pcms,
 	.init = stac92xx_init,
@@ -5588,7 +5594,7 @@ static int stac_hp_bass_gpio_put(struct snd_kcontrol *kcontrol,
 	return 1;
 }
 
-static struct snd_kcontrol_new stac_hp_bass_sw_ctrl = {
+static const struct snd_kcontrol_new stac_hp_bass_sw_ctrl = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.info = stac_hp_bass_gpio_info,
 	.get = stac_hp_bass_gpio_get,
@@ -5612,7 +5618,7 @@ static int stac_add_hp_bass_switch(struct hda_codec *codec)
 static int patch_stac92hd71bxx(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
-	struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init;
+	const struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init;
 	unsigned int pin_cfg;
 	int err = 0;
 
@@ -5705,9 +5711,9 @@ again:
 		unmute_init++;
 		snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
 		snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
-		stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS - 1] = 0;
+		spec->dmic_nids = stac92hd71bxx_dmic_5port_nids;
 		spec->num_dmics = stac92xx_connected_ports(codec,
-					stac92hd71bxx_dmic_nids,
+					stac92hd71bxx_dmic_5port_nids,
 					STAC92HD71BXX_NUM_DMICS - 1);
 		break;
 	case 0x111d7603: /* 6 Port with Analog Mixer */
@@ -5729,15 +5735,6 @@ again:
 	if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
 		snd_hda_sequence_write_cache(codec, unmute_init);
 
-	/* Some HP machines seem to have unstable codec communications
-	 * especially with ATI fglrx driver.  For recovering from the
-	 * CORB/RIRB stall, allow the BUS reset and keep always sync
-	 */
-	if (spec->board_config == STAC_HP_DV5) {
-		codec->bus->sync_write = 1;
-		codec->bus->allow_bus_reset = 1;
-	}
-
 	spec->aloopback_ctl = stac92hd71bxx_loopback;
 	spec->aloopback_mask = 0x50;
 	spec->aloopback_shift = 0;
@@ -6223,31 +6220,31 @@ static int patch_stac9205(struct hda_codec *codec)
  * STAC9872 hack
  */
 
-static struct hda_verb stac9872_core_init[] = {
+static const struct hda_verb stac9872_core_init[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
 	{}
 };
 
-static hda_nid_t stac9872_pin_nids[] = {
+static const hda_nid_t stac9872_pin_nids[] = {
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
 	0x11, 0x13, 0x14,
 };
 
-static hda_nid_t stac9872_adc_nids[] = {
+static const hda_nid_t stac9872_adc_nids[] = {
 	0x8 /*,0x6*/
 };
 
-static hda_nid_t stac9872_mux_nids[] = {
+static const hda_nid_t stac9872_mux_nids[] = {
 	0x15
 };
 
-static unsigned long stac9872_capvols[] = {
+static const unsigned long stac9872_capvols[] = {
 	HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
 };
 #define stac9872_capsws		stac9872_capvols
 
-static unsigned int stac9872_vaio_pin_configs[9] = {
+static const unsigned int stac9872_vaio_pin_configs[9] = {
 	0x03211020, 0x411111f0, 0x411111f0, 0x03a15030,
 	0x411111f0, 0x90170110, 0x411111f0, 0x411111f0,
 	0x90a7013e
@@ -6258,11 +6255,11 @@ static const char * const stac9872_models[STAC_9872_MODELS] = {
 	[STAC_9872_VAIO] = "vaio",
 };
 
-static unsigned int *stac9872_brd_tbl[STAC_9872_MODELS] = {
+static const unsigned int *stac9872_brd_tbl[STAC_9872_MODELS] = {
 	[STAC_9872_VAIO] = stac9872_vaio_pin_configs,
 };
 
-static struct snd_pci_quirk stac9872_cfg_tbl[] = {
+static const struct snd_pci_quirk stac9872_cfg_tbl[] = {
 	SND_PCI_QUIRK_MASK(0x104d, 0xfff0, 0x81e0,
 			   "Sony VAIO F/S", STAC_9872_VAIO),
 	{} /* terminator */
@@ -6316,7 +6313,7 @@ static int patch_stac9872(struct hda_codec *codec)
 /*
  * patch entries
  */
-static struct hda_codec_preset snd_hda_preset_sigmatel[] = {
+static const struct hda_codec_preset snd_hda_preset_sigmatel[] = {
  	{ .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
  	{ .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
  	{ .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 0997031c48d2..605c99e1e520 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -98,24 +98,30 @@ enum VIA_HDA_CODEC {
 	VT1716S,
 	VT2002P,
 	VT1812,
+	VT1802,
 	CODEC_TYPES,
 };
 
+#define VT2002P_COMPATIBLE(spec) \
+	((spec)->codec_type == VT2002P ||\
+	 (spec)->codec_type == VT1812 ||\
+	 (spec)->codec_type == VT1802)
+
 struct via_spec {
 	/* codec parameterization */
-	struct snd_kcontrol_new *mixers[6];
+	const struct snd_kcontrol_new *mixers[6];
 	unsigned int num_mixers;
 
-	struct hda_verb *init_verbs[5];
+	const struct hda_verb *init_verbs[5];
 	unsigned int num_iverbs;
 
 	char *stream_name_analog;
-	struct hda_pcm_stream *stream_analog_playback;
-	struct hda_pcm_stream *stream_analog_capture;
+	const struct hda_pcm_stream *stream_analog_playback;
+	const struct hda_pcm_stream *stream_analog_capture;
 
 	char *stream_name_digital;
-	struct hda_pcm_stream *stream_digital_playback;
-	struct hda_pcm_stream *stream_digital_capture;
+	const struct hda_pcm_stream *stream_digital_playback;
+	const struct hda_pcm_stream *stream_digital_capture;
 
 	/* playback */
 	struct hda_multi_out multiout;
@@ -123,7 +129,7 @@ struct via_spec {
 
 	/* capture */
 	unsigned int num_adc_nids;
-	hda_nid_t *adc_nids;
+	const hda_nid_t *adc_nids;
 	hda_nid_t mux_nids[3];
 	hda_nid_t dig_in_nid;
 	hda_nid_t dig_in_pin;
@@ -154,6 +160,9 @@ struct via_spec {
 	struct delayed_work vt1708_hp_work;
 	int vt1708_jack_detectect;
 	int vt1708_hp_present;
+
+	void (*set_widgets_power_state)(struct hda_codec *codec);
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	struct hda_loopback_check loopback;
 #endif
@@ -218,17 +227,19 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
 		codec_type = VT1812;
 	else if (dev_id == 0x0440)
 		codec_type = VT1708S;
+	else if ((dev_id & 0xfff) == 0x446)
+		codec_type = VT1802;
 	else
 		codec_type = UNKNOWN;
 	return codec_type;
 };
 
+#define VIA_JACK_EVENT		0x20
 #define VIA_HP_EVENT		0x01
 #define VIA_GPIO_EVENT		0x02
-#define VIA_JACK_EVENT		0x04
-#define VIA_MONO_EVENT		0x08
-#define VIA_SPEAKER_EVENT	0x10
-#define VIA_BIND_HP_EVENT	0x20
+#define VIA_MONO_EVENT		0x03
+#define VIA_SPEAKER_EVENT	0x04
+#define VIA_BIND_HP_EVENT	0x05
 
 enum {
 	VIA_CTL_WIDGET_VOL,
@@ -245,7 +256,6 @@ enum {
 };
 
 static void analog_low_current_mode(struct hda_codec *codec, int stream_idle);
-static void set_jack_power_state(struct hda_codec *codec);
 static int is_aa_path_mute(struct hda_codec *codec);
 
 static void vt1708_start_hp_work(struct via_spec *spec)
@@ -271,6 +281,12 @@ static void vt1708_stop_hp_work(struct via_spec *spec)
 	cancel_delayed_work_sync(&spec->vt1708_hp_work);
 }
 
+static void set_widgets_power_state(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	if (spec->set_widgets_power_state)
+		spec->set_widgets_power_state(codec);
+}
 
 static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_value *ucontrol)
@@ -278,7 +294,7 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
 	int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 
-	set_jack_power_state(codec);
+	set_widgets_power_state(codec);
 	analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1);
 	if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) {
 		if (is_aa_path_mute(codec))
@@ -394,54 +410,54 @@ static int bind_pin_switch_put(struct snd_kcontrol *kcontrol,
 			.put = bind_pin_switch_put,			\
 			.private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
 
-static struct snd_kcontrol_new via_control_templates[] = {
+static const struct snd_kcontrol_new via_control_templates[] = {
 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
 	HDA_CODEC_MUTE(NULL, 0, 0, 0),
 	ANALOG_INPUT_MUTE,
 	BIND_PIN_MUTE,
 };
 
-static hda_nid_t vt1708_adc_nids[2] = {
+static const hda_nid_t vt1708_adc_nids[2] = {
 	/* ADC1-2 */
 	0x15, 0x27
 };
 
-static hda_nid_t vt1709_adc_nids[3] = {
+static const hda_nid_t vt1709_adc_nids[3] = {
 	/* ADC1-2 */
 	0x14, 0x15, 0x16
 };
 
-static hda_nid_t vt1708B_adc_nids[2] = {
+static const hda_nid_t vt1708B_adc_nids[2] = {
 	/* ADC1-2 */
 	0x13, 0x14
 };
 
-static hda_nid_t vt1708S_adc_nids[2] = {
+static const hda_nid_t vt1708S_adc_nids[2] = {
 	/* ADC1-2 */
 	0x13, 0x14
 };
 
-static hda_nid_t vt1702_adc_nids[3] = {
+static const hda_nid_t vt1702_adc_nids[3] = {
 	/* ADC1-2 */
 	0x12, 0x20, 0x1F
 };
 
-static hda_nid_t vt1718S_adc_nids[2] = {
+static const hda_nid_t vt1718S_adc_nids[2] = {
 	/* ADC1-2 */
 	0x10, 0x11
 };
 
-static hda_nid_t vt1716S_adc_nids[2] = {
+static const hda_nid_t vt1716S_adc_nids[2] = {
 	/* ADC1-2 */
 	0x13, 0x14
 };
 
-static hda_nid_t vt2002P_adc_nids[2] = {
+static const hda_nid_t vt2002P_adc_nids[2] = {
 	/* ADC1-2 */
 	0x10, 0x11
 };
 
-static hda_nid_t vt1812_adc_nids[2] = {
+static const hda_nid_t vt1812_adc_nids[2] = {
 	/* ADC1-2 */
 	0x10, 0x11
 };
@@ -471,7 +487,7 @@ static int __via_add_control(struct via_spec *spec, int type, const char *name,
 	__via_add_control(spec, type, name, 0, val)
 
 static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec,
-						struct snd_kcontrol_new *tmpl)
+				const struct snd_kcontrol_new *tmpl)
 {
 	struct snd_kcontrol_new *knew;
 
@@ -602,482 +618,6 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm);
 }
 
-static void set_jack_power_state(struct hda_codec *codec)
-{
-	struct via_spec *spec = codec->spec;
-	int imux_is_smixer;
-	unsigned int parm;
-
-	if (spec->codec_type == VT1702) {
-		imux_is_smixer = snd_hda_codec_read(
-			codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
-		/* inputs */
-		/* PW 1/2/5 (14h/15h/18h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x14, &parm);
-		set_pin_power_state(codec, 0x15, &parm);
-		set_pin_power_state(codec, 0x18, &parm);
-		if (imux_is_smixer)
-			parm = AC_PWRST_D0; /* SW0 = stereo mixer (idx 3) */
-		/* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */
-		snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* outputs */
-		/* PW 3/4 (16h/17h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x16, &parm);
-		set_pin_power_state(codec, 0x17, &parm);
-		/* MW0 (1ah), AOW 0/1 (10h/1dh) */
-		snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
-				    imux_is_smixer ? AC_PWRST_D0 : parm);
-		snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-	} else if (spec->codec_type == VT1708B_8CH
-		   || spec->codec_type == VT1708B_4CH
-		   || spec->codec_type == VT1708S) {
-		/* SW0 (17h) = stereo mixer */
-		int is_8ch = spec->codec_type != VT1708B_4CH;
-		imux_is_smixer = snd_hda_codec_read(
-			codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00)
-			== ((spec->codec_type == VT1708S)  ? 5 : 0);
-		/* inputs */
-		/* PW 1/2/5 (1ah/1bh/1eh) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x1a, &parm);
-		set_pin_power_state(codec, 0x1b, &parm);
-		set_pin_power_state(codec, 0x1e, &parm);
-		if (imux_is_smixer)
-			parm = AC_PWRST_D0;
-		/* SW0 (17h), AIW 0/1 (13h/14h) */
-		snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* outputs */
-		/* PW0 (19h), SW1 (18h), AOW1 (11h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x19, &parm);
-		if (spec->smart51_enabled)
-			parm = AC_PWRST_D0;
-		snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* PW6 (22h), SW2 (26h), AOW2 (24h) */
-		if (is_8ch) {
-			parm = AC_PWRST_D3;
-			set_pin_power_state(codec, 0x22, &parm);
-			if (spec->smart51_enabled)
-				parm = AC_PWRST_D0;
-			snd_hda_codec_write(codec, 0x26, 0,
-					    AC_VERB_SET_POWER_STATE, parm);
-			snd_hda_codec_write(codec, 0x24, 0,
-					    AC_VERB_SET_POWER_STATE, parm);
-		}
-
-		/* PW 3/4/7 (1ch/1dh/23h) */
-		parm = AC_PWRST_D3;
-		/* force to D0 for internal Speaker */
-		set_pin_power_state(codec, 0x1c, &parm);
-		set_pin_power_state(codec, 0x1d, &parm);
-		if (is_8ch)
-			set_pin_power_state(codec, 0x23, &parm);
-		/* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */
-		snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
-				    imux_is_smixer ? AC_PWRST_D0 : parm);
-		snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		if (is_8ch) {
-			snd_hda_codec_write(codec, 0x25, 0,
-					    AC_VERB_SET_POWER_STATE, parm);
-			snd_hda_codec_write(codec, 0x27, 0,
-					    AC_VERB_SET_POWER_STATE, parm);
-		}
-	}  else if (spec->codec_type == VT1718S) {
-		/* MUX6 (1eh) = stereo mixer */
-		imux_is_smixer = snd_hda_codec_read(
-			codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
-		/* inputs */
-		/* PW 5/6/7 (29h/2ah/2bh) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x29, &parm);
-		set_pin_power_state(codec, 0x2a, &parm);
-		set_pin_power_state(codec, 0x2b, &parm);
-		if (imux_is_smixer)
-			parm = AC_PWRST_D0;
-		/* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */
-		snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* outputs */
-		/* PW3 (27h), MW2 (1ah), AOW3 (bh) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x27, &parm);
-		snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* PW2 (26h), AOW2 (ah) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x26, &parm);
-		snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* PW0/1 (24h/25h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x24, &parm);
-		set_pin_power_state(codec, 0x25, &parm);
-		if (!spec->hp_independent_mode) /* check for redirected HP */
-			set_pin_power_state(codec, 0x28, &parm);
-		snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		/* MW9 (21h), Mw2 (1ah), AOW0 (8h) */
-		snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE,
-				    imux_is_smixer ? AC_PWRST_D0 : parm);
-		if (spec->hp_independent_mode) {
-			/* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */
-			parm = AC_PWRST_D3;
-			set_pin_power_state(codec, 0x28, &parm);
-			snd_hda_codec_write(codec, 0x1b, 0,
-					    AC_VERB_SET_POWER_STATE, parm);
-			snd_hda_codec_write(codec, 0x34, 0,
-					    AC_VERB_SET_POWER_STATE, parm);
-			snd_hda_codec_write(codec, 0xc, 0,
-					    AC_VERB_SET_POWER_STATE, parm);
-		}
-	} else if (spec->codec_type == VT1716S) {
-		unsigned int mono_out, present;
-		/* SW0 (17h) = stereo mixer */
-		imux_is_smixer = snd_hda_codec_read(
-			codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) ==  5;
-		/* inputs */
-		/* PW 1/2/5 (1ah/1bh/1eh) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x1a, &parm);
-		set_pin_power_state(codec, 0x1b, &parm);
-		set_pin_power_state(codec, 0x1e, &parm);
-		if (imux_is_smixer)
-			parm = AC_PWRST_D0;
-		/* SW0 (17h), AIW0(13h) */
-		snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x1e, &parm);
-		/* PW11 (22h) */
-		if (spec->dmic_enabled)
-			set_pin_power_state(codec, 0x22, &parm);
-		else
-			snd_hda_codec_write(
-				codec, 0x22, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-
-		/* SW2(26h), AIW1(14h) */
-		snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* outputs */
-		/* PW0 (19h), SW1 (18h), AOW1 (11h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x19, &parm);
-		/* Smart 5.1 PW2(1bh) */
-		if (spec->smart51_enabled)
-			set_pin_power_state(codec, 0x1b, &parm);
-		snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* PW7 (23h), SW3 (27h), AOW3 (25h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x23, &parm);
-		/* Smart 5.1 PW1(1ah) */
-		if (spec->smart51_enabled)
-			set_pin_power_state(codec, 0x1a, &parm);
-		snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* Smart 5.1 PW5(1eh) */
-		if (spec->smart51_enabled)
-			set_pin_power_state(codec, 0x1e, &parm);
-		snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* Mono out */
-		/* SW4(28h)->MW1(29h)-> PW12 (2ah)*/
-		present = snd_hda_jack_detect(codec, 0x1c);
-		if (present)
-			mono_out = 0;
-		else {
-			present = snd_hda_jack_detect(codec, 0x1d);
-			if (!spec->hp_independent_mode && present)
-				mono_out = 0;
-			else
-				mono_out = 1;
-		}
-		parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3;
-		snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* PW 3/4 (1ch/1dh) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x1c, &parm);
-		set_pin_power_state(codec, 0x1d, &parm);
-		/* HP Independent Mode, power on AOW3 */
-		if (spec->hp_independent_mode)
-			snd_hda_codec_write(codec, 0x25, 0,
-					    AC_VERB_SET_POWER_STATE, parm);
-
-		/* force to D0 for internal Speaker */
-		/* MW0 (16h), AOW0 (10h) */
-		snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
-				    imux_is_smixer ? AC_PWRST_D0 : parm);
-		snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
-				    mono_out ? AC_PWRST_D0 : parm);
-	} else if (spec->codec_type == VT2002P) {
-		unsigned int present;
-		/* MUX9 (1eh) = stereo mixer */
-		imux_is_smixer = snd_hda_codec_read(
-			codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
-		/* inputs */
-		/* PW 5/6/7 (29h/2ah/2bh) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x29, &parm);
-		set_pin_power_state(codec, 0x2a, &parm);
-		set_pin_power_state(codec, 0x2b, &parm);
-		if (imux_is_smixer)
-			parm = AC_PWRST_D0;
-		/* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */
-		snd_hda_codec_write(codec, 0x1e, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x1f, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x10, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x11, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-
-		/* outputs */
-		/* AOW0 (8h)*/
-		snd_hda_codec_write(codec, 0x8, 0,
-				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-
-		/* PW4 (26h), MW4 (1ch), MUX4(37h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x26, &parm);
-		snd_hda_codec_write(codec, 0x1c, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x37,
-				    0, AC_VERB_SET_POWER_STATE, parm);
-
-		/* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x25, &parm);
-		snd_hda_codec_write(codec, 0x19, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x35, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		if (spec->hp_independent_mode)	{
-			snd_hda_codec_write(codec, 0x9, 0,
-					    AC_VERB_SET_POWER_STATE, parm);
-		}
-
-		/* Class-D */
-		/* PW0 (24h), MW0(18h), MUX0(34h) */
-		present = snd_hda_jack_detect(codec, 0x25);
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x24, &parm);
-		if (present) {
-			snd_hda_codec_write(
-				codec, 0x18, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-			snd_hda_codec_write(
-				codec, 0x34, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-		} else {
-			snd_hda_codec_write(
-				codec, 0x18, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-			snd_hda_codec_write(
-				codec, 0x34, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-		}
-
-		/* Mono Out */
-		/* PW15 (31h), MW8(17h), MUX8(3bh) */
-		present = snd_hda_jack_detect(codec, 0x26);
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x31, &parm);
-		if (present) {
-			snd_hda_codec_write(
-				codec, 0x17, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-			snd_hda_codec_write(
-				codec, 0x3b, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-		} else {
-			snd_hda_codec_write(
-				codec, 0x17, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-			snd_hda_codec_write(
-				codec, 0x3b, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-		}
-
-		/* MW9 (21h) */
-		if (imux_is_smixer || !is_aa_path_mute(codec))
-			snd_hda_codec_write(
-				codec, 0x21, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-		else
-			snd_hda_codec_write(
-				codec, 0x21, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-	} else if (spec->codec_type == VT1812) {
-		unsigned int present;
-		/* MUX10 (1eh) = stereo mixer */
-		imux_is_smixer = snd_hda_codec_read(
-			codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
-		/* inputs */
-		/* PW 5/6/7 (29h/2ah/2bh) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x29, &parm);
-		set_pin_power_state(codec, 0x2a, &parm);
-		set_pin_power_state(codec, 0x2b, &parm);
-		if (imux_is_smixer)
-			parm = AC_PWRST_D0;
-		/* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */
-		snd_hda_codec_write(codec, 0x1e, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x1f, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x10, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x11, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-
-		/* outputs */
-		/* AOW0 (8h)*/
-		snd_hda_codec_write(codec, 0x8, 0,
-				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-
-		/* PW4 (28h), MW4 (18h), MUX4(38h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x28, &parm);
-		snd_hda_codec_write(codec, 0x18, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x38, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-
-		/* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x25, &parm);
-		snd_hda_codec_write(codec, 0x15, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x35, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		if (spec->hp_independent_mode)	{
-			snd_hda_codec_write(codec, 0x9, 0,
-					    AC_VERB_SET_POWER_STATE, parm);
-		}
-
-		/* Internal Speaker */
-		/* PW0 (24h), MW0(14h), MUX0(34h) */
-		present = snd_hda_jack_detect(codec, 0x25);
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x24, &parm);
-		if (present) {
-			snd_hda_codec_write(codec, 0x14, 0,
-					    AC_VERB_SET_POWER_STATE,
-					    AC_PWRST_D3);
-			snd_hda_codec_write(codec, 0x34, 0,
-					    AC_VERB_SET_POWER_STATE,
-					    AC_PWRST_D3);
-		} else {
-			snd_hda_codec_write(codec, 0x14, 0,
-					    AC_VERB_SET_POWER_STATE,
-					    AC_PWRST_D0);
-			snd_hda_codec_write(codec, 0x34, 0,
-					    AC_VERB_SET_POWER_STATE,
-					    AC_PWRST_D0);
-		}
-		/* Mono Out */
-		/* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */
-		present = snd_hda_jack_detect(codec, 0x28);
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x31, &parm);
-		if (present) {
-			snd_hda_codec_write(codec, 0x1c, 0,
-					    AC_VERB_SET_POWER_STATE,
-					    AC_PWRST_D3);
-			snd_hda_codec_write(codec, 0x3c, 0,
-					    AC_VERB_SET_POWER_STATE,
-					    AC_PWRST_D3);
-			snd_hda_codec_write(codec, 0x3e, 0,
-					    AC_VERB_SET_POWER_STATE,
-					    AC_PWRST_D3);
-		} else {
-			snd_hda_codec_write(codec, 0x1c, 0,
-					    AC_VERB_SET_POWER_STATE,
-					    AC_PWRST_D0);
-			snd_hda_codec_write(codec, 0x3c, 0,
-					    AC_VERB_SET_POWER_STATE,
-					    AC_PWRST_D0);
-			snd_hda_codec_write(codec, 0x3e, 0,
-					    AC_VERB_SET_POWER_STATE,
-					    AC_PWRST_D0);
-		}
-
-		/* PW15 (33h), MW15 (1dh), MUX15(3dh) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x33, &parm);
-		snd_hda_codec_write(codec, 0x1d, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x3d, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-
-		/* MW9 (21h) */
-		if (imux_is_smixer || !is_aa_path_mute(codec))
-			snd_hda_codec_write(
-				codec, 0x21, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-		else
-			snd_hda_codec_write(
-				codec, 0x21, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-	}
-}
-
 /*
  * input MUX handling
  */
@@ -1120,7 +660,7 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
 				     spec->mux_nids[adc_idx],
 				     &spec->cur_mux[adc_idx]);
 	/* update jack power state */
-	set_jack_power_state(codec);
+	set_widgets_power_state(codec);
 
 	return ret;
 }
@@ -1168,6 +708,9 @@ static hda_nid_t side_mute_channel(struct via_spec *spec)
 	case VT1709_10CH:	return 0x29;
 	case VT1708B_8CH:	/* fall thru */
 	case VT1708S:		return 0x27;
+	case VT2002P:		return 0x19;
+	case VT1802:		return 0x15;
+	case VT1812:		return 0x15;
 	default:		return 0;
 	}
 }
@@ -1176,13 +719,22 @@ static int update_side_mute_status(struct hda_codec *codec)
 {
 	/* mute side channel */
 	struct via_spec *spec = codec->spec;
-	unsigned int parm = spec->hp_independent_mode
-		? AMP_OUT_MUTE : AMP_OUT_UNMUTE;
+	unsigned int parm;
 	hda_nid_t sw3 = side_mute_channel(spec);
 
-	if (sw3)
-		snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-				    parm);
+	if (sw3) {
+		if (VT2002P_COMPATIBLE(spec))
+			parm = spec->hp_independent_mode ?
+			       AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1);
+		else
+			parm = spec->hp_independent_mode ?
+			       AMP_OUT_MUTE : AMP_OUT_UNMUTE;
+		snd_hda_codec_write(codec, sw3, 0,
+				    AC_VERB_SET_AMP_GAIN_MUTE, parm);
+		if (spec->codec_type == VT1812)
+			snd_hda_codec_write(codec, 0x1d, 0,
+					    AC_VERB_SET_AMP_GAIN_MUTE, parm);
+	}
 	return 0;
 }
 
@@ -1217,19 +769,18 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
 	    || spec->codec_type == VT1702
 	    || spec->codec_type == VT1718S
 	    || spec->codec_type == VT1716S
-	    || spec->codec_type == VT2002P
-	    || spec->codec_type == VT1812) {
+	    || VT2002P_COMPATIBLE(spec)) {
 		activate_ctl(codec, "Headphone Playback Volume",
 			     spec->hp_independent_mode);
 		activate_ctl(codec, "Headphone Playback Switch",
 			     spec->hp_independent_mode);
 	}
 	/* update jack power state */
-	set_jack_power_state(codec);
+	set_widgets_power_state(codec);
 	return 0;
 }
 
-static struct snd_kcontrol_new via_hp_mixer[2] = {
+static const struct snd_kcontrol_new via_hp_mixer[2] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Independent HP",
@@ -1256,6 +807,7 @@ static int via_hp_build(struct hda_codec *codec)
 		nid = 0x34;
 		break;
 	case VT2002P:
+	case VT1802:
 		nid = 0x35;
 		break;
 	case VT1812:
@@ -1447,11 +999,11 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol,
 		}
 	}
 	spec->smart51_enabled = *ucontrol->value.integer.value;
-	set_jack_power_state(codec);
+	set_widgets_power_state(codec);
 	return 1;
 }
 
-static struct snd_kcontrol_new via_smart51_mixer[2] = {
+static const struct snd_kcontrol_new via_smart51_mixer[2] = {
 	{
 	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	 .name = "Smart 5.1",
@@ -1473,6 +1025,11 @@ static int via_smart51_build(struct via_spec *spec)
 	hda_nid_t nid;
 	int i;
 
+	if (!cfg)
+		return 0;
+	if (cfg->line_outs > 2)
+		return 0;
+
 	knew = via_clone_control(spec, &via_smart51_mixer[0]);
 	if (knew == NULL)
 		return -ENOMEM;
@@ -1492,7 +1049,7 @@ static int via_smart51_build(struct via_spec *spec)
 }
 
 /* capture mixer elements */
-static struct snd_kcontrol_new vt1708_capture_mixer[] = {
+static const struct snd_kcontrol_new vt1708_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
@@ -1543,6 +1100,7 @@ static int is_aa_path_mute(struct hda_codec *codec)
 		break;
 	case VT2002P:
 	case VT1812:
+	case VT1802:
 		nid_mixer = 0x21;
 		start_idx = 0;
 		end_idx = 2;
@@ -1607,6 +1165,7 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle)
 		break;
 	case VT2002P:
 	case VT1812:
+	case VT1802:
 		verb = 0xf93;
 		parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */
 		break;
@@ -1620,7 +1179,7 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle)
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
-static struct hda_verb vt1708_volume_init_verbs[] = {
+static const struct hda_verb vt1708_volume_init_verbs[] = {
 	/*
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 */
@@ -1650,6 +1209,8 @@ static struct hda_verb vt1708_volume_init_verbs[] = {
 	{0x20, AC_VERB_SET_CONNECT_SEL, 0},
 	/* PW9 Output enable */
 	{0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	/* power down jack detect function */
+	{0x1, 0xf81, 0x1},
 	{ }
 };
 
@@ -1672,7 +1233,7 @@ static void playback_multi_pcm_prep_0(struct hda_codec *codec,
 {
 	struct via_spec *spec = codec->spec;
 	struct hda_multi_out *mout = &spec->multiout;
-	hda_nid_t *nids = mout->dac_nids;
+	const hda_nid_t *nids = mout->dac_nids;
 	int chs = substream->runtime->channels;
 	int i;
 
@@ -1741,7 +1302,7 @@ static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
 {
 	struct via_spec *spec = codec->spec;
 	struct hda_multi_out *mout = &spec->multiout;
-	hda_nid_t *nids = mout->dac_nids;
+	const hda_nid_t *nids = mout->dac_nids;
 
 	if (substream->number == 0)
 		playback_multi_pcm_prep_0(codec, stream_tag, format,
@@ -1762,7 +1323,7 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
 {
 	struct via_spec *spec = codec->spec;
 	struct hda_multi_out *mout = &spec->multiout;
-	hda_nid_t *nids = mout->dac_nids;
+	const hda_nid_t *nids = mout->dac_nids;
 	int i;
 
 	if (substream->number == 0) {
@@ -1860,7 +1421,7 @@ static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 	return 0;
 }
 
-static struct hda_pcm_stream vt1708_pcm_analog_playback = {
+static const struct hda_pcm_stream vt1708_pcm_analog_playback = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 8,
@@ -1872,7 +1433,7 @@ static struct hda_pcm_stream vt1708_pcm_analog_playback = {
 	},
 };
 
-static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
+static const struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 8,
@@ -1889,7 +1450,7 @@ static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
 	},
 };
 
-static struct hda_pcm_stream vt1708_pcm_analog_capture = {
+static const struct hda_pcm_stream vt1708_pcm_analog_capture = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -1900,7 +1461,7 @@ static struct hda_pcm_stream vt1708_pcm_analog_capture = {
 	},
 };
 
-static struct hda_pcm_stream vt1708_pcm_digital_playback = {
+static const struct hda_pcm_stream vt1708_pcm_digital_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -1913,7 +1474,7 @@ static struct hda_pcm_stream vt1708_pcm_digital_playback = {
 	},
 };
 
-static struct hda_pcm_stream vt1708_pcm_digital_capture = {
+static const struct hda_pcm_stream vt1708_pcm_digital_capture = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -1923,7 +1484,7 @@ static int via_build_controls(struct hda_codec *codec)
 {
 	struct via_spec *spec = codec->spec;
 	struct snd_kcontrol *kctl;
-	struct snd_kcontrol_new *knew;
+	const struct snd_kcontrol_new *knew;
 	int err, i;
 
 	for (i = 0; i < spec->num_mixers; i++) {
@@ -1971,7 +1532,7 @@ static int via_build_controls(struct hda_codec *codec)
 	}
 
 	/* init power states */
-	set_jack_power_state(codec);
+	set_widgets_power_state(codec);
 	analog_low_current_mode(codec, 1);
 
 	via_free_kctls(codec); /* no longer needed */
@@ -2135,7 +1696,7 @@ static void via_speaker_automute(struct hda_codec *codec)
 	unsigned int hp_present;
 	struct via_spec *spec = codec->spec;
 
-	if (spec->codec_type != VT2002P && spec->codec_type != VT1812)
+	if (!VT2002P_COMPATIBLE(spec))
 		return;
 
 	hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
@@ -2194,17 +1755,21 @@ static void via_unsol_event(struct hda_codec *codec,
 				  unsigned int res)
 {
 	res >>= 26;
-	if (res & VIA_HP_EVENT)
+
+	if (res & VIA_JACK_EVENT)
+		set_widgets_power_state(codec);
+
+	res &= ~VIA_JACK_EVENT;
+
+	if (res == VIA_HP_EVENT)
 		via_hp_automute(codec);
-	if (res & VIA_GPIO_EVENT)
+	else if (res == VIA_GPIO_EVENT)
 		via_gpio_control(codec);
-	if (res & VIA_JACK_EVENT)
-		set_jack_power_state(codec);
-	if (res & VIA_MONO_EVENT)
+	else if (res == VIA_MONO_EVENT)
 		via_mono_automute(codec);
-	if (res & VIA_SPEAKER_EVENT)
+	else if (res == VIA_SPEAKER_EVENT)
 		via_speaker_automute(codec);
-	if (res & VIA_BIND_HP_EVENT)
+	else if (res == VIA_BIND_HP_EVENT)
 		via_hp_bind_automute(codec);
 }
 
@@ -2254,7 +1819,7 @@ static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
 
 /*
  */
-static struct hda_codec_ops via_patch_ops = {
+static const struct hda_codec_ops via_patch_ops = {
 	.build_controls = via_build_controls,
 	.build_pcms = via_build_pcms,
 	.init = via_init,
@@ -2284,16 +1849,16 @@ static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
 			/* config dac list */
 			switch (i) {
 			case AUTO_SEQ_FRONT:
-				spec->multiout.dac_nids[i] = 0x10;
+				spec->private_dac_nids[i] = 0x10;
 				break;
 			case AUTO_SEQ_CENLFE:
-				spec->multiout.dac_nids[i] = 0x12;
+				spec->private_dac_nids[i] = 0x12;
 				break;
 			case AUTO_SEQ_SURROUND:
-				spec->multiout.dac_nids[i] = 0x11;
+				spec->private_dac_nids[i] = 0x11;
 				break;
 			case AUTO_SEQ_SIDE:
-				spec->multiout.dac_nids[i] = 0x13;
+				spec->private_dac_nids[i] = 0x13;
 				break;
 			}
 		}
@@ -2437,7 +2002,8 @@ static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 static int vt_auto_create_analog_input_ctls(struct hda_codec *codec,
 					    const struct auto_pin_cfg *cfg,
 					    hda_nid_t cap_nid,
-					    hda_nid_t pin_idxs[], int num_idxs)
+					    const hda_nid_t pin_idxs[],
+					    int num_idxs)
 {
 	struct via_spec *spec = codec->spec;
 	struct hda_input_mux *imux = &spec->private_imux[0];
@@ -2483,13 +2049,13 @@ static int vt_auto_create_analog_input_ctls(struct hda_codec *codec,
 static int vt1708_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 {
-	static hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 };
+	static const hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 };
 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x17, pin_idxs,
 						ARRAY_SIZE(pin_idxs));
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list vt1708_loopbacks[] = {
+static const struct hda_amp_list vt1708_loopbacks[] = {
 	{ 0x17, HDA_INPUT, 1 },
 	{ 0x17, HDA_INPUT, 2 },
 	{ 0x17, HDA_INPUT, 3 },
@@ -2548,7 +2114,7 @@ static int vt1708_jack_detectect_put(struct snd_kcontrol *kcontrol,
 	return change;
 }
 
-static struct snd_kcontrol_new vt1708_jack_detectect[] = {
+static const struct snd_kcontrol_new vt1708_jack_detectect[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Jack Detect",
@@ -2623,7 +2189,8 @@ static int via_auto_init(struct hda_codec *codec)
 	via_auto_init_multi_out(codec);
 	via_auto_init_hp_out(codec);
 	via_auto_init_analog_input(codec);
-	if (spec->codec_type == VT2002P || spec->codec_type == VT1812) {
+
+	if (VT2002P_COMPATIBLE(spec)) {
 		via_hp_bind_automute(codec);
 	} else {
 		via_hp_automute(codec);
@@ -2727,7 +2294,7 @@ static int patch_vt1708(struct hda_codec *codec)
 }
 
 /* capture mixer elements */
-static struct snd_kcontrol_new vt1709_capture_mixer[] = {
+static const struct snd_kcontrol_new vt1709_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
@@ -2749,7 +2316,7 @@ static struct snd_kcontrol_new vt1709_capture_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb vt1709_uniwill_init_verbs[] = {
+static const struct hda_verb vt1709_uniwill_init_verbs[] = {
 	{0x20, AC_VERB_SET_UNSOLICITED_ENABLE,
 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
 	{ }
@@ -2758,7 +2325,7 @@ static struct hda_verb vt1709_uniwill_init_verbs[] = {
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
-static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
+static const struct hda_verb vt1709_10ch_volume_init_verbs[] = {
 	/*
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 */
@@ -2798,7 +2365,7 @@ static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
 	{ }
 };
 
-static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
+static const struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 10,
@@ -2810,7 +2377,7 @@ static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
 	},
 };
 
-static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
+static const struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 6,
@@ -2822,7 +2389,7 @@ static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
 	},
 };
 
-static struct hda_pcm_stream vt1709_pcm_analog_capture = {
+static const struct hda_pcm_stream vt1709_pcm_analog_capture = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -2833,7 +2400,7 @@ static struct hda_pcm_stream vt1709_pcm_analog_capture = {
 	},
 };
 
-static struct hda_pcm_stream vt1709_pcm_digital_playback = {
+static const struct hda_pcm_stream vt1709_pcm_digital_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -2844,7 +2411,7 @@ static struct hda_pcm_stream vt1709_pcm_digital_playback = {
 	},
 };
 
-static struct hda_pcm_stream vt1709_pcm_digital_capture = {
+static const struct hda_pcm_stream vt1709_pcm_digital_capture = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -2871,26 +2438,26 @@ static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
 				switch (i) {
 				case AUTO_SEQ_FRONT:
 					/* AOW0 */
-					spec->multiout.dac_nids[i] = 0x10;
+					spec->private_dac_nids[i] = 0x10;
 					break;
 				case AUTO_SEQ_CENLFE:
 					/* AOW2 */
-					spec->multiout.dac_nids[i] = 0x12;
+					spec->private_dac_nids[i] = 0x12;
 					break;
 				case AUTO_SEQ_SURROUND:
 					/* AOW3 */
-					spec->multiout.dac_nids[i] = 0x11;
+					spec->private_dac_nids[i] = 0x11;
 					break;
 				case AUTO_SEQ_SIDE:
 					/* AOW1 */
-					spec->multiout.dac_nids[i] = 0x27;
+					spec->private_dac_nids[i] = 0x27;
 					break;
 				default:
 					break;
 				}
 			}
 		}
-		spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
+		spec->private_dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
 
 	} else if (cfg->line_outs == 3) { /* 6 channels */
 		for (i = 0; i < cfg->line_outs; i++) {
@@ -2900,15 +2467,15 @@ static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
 				switch (i) {
 				case AUTO_SEQ_FRONT:
 					/* AOW0 */
-					spec->multiout.dac_nids[i] = 0x10;
+					spec->private_dac_nids[i] = 0x10;
 					break;
 				case AUTO_SEQ_CENLFE:
 					/* AOW2 */
-					spec->multiout.dac_nids[i] = 0x12;
+					spec->private_dac_nids[i] = 0x12;
 					break;
 				case AUTO_SEQ_SURROUND:
 					/* AOW1 */
-					spec->multiout.dac_nids[i] = 0x11;
+					spec->private_dac_nids[i] = 0x11;
 					break;
 				default:
 					break;
@@ -3056,7 +2623,7 @@ static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 static int vt1709_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 {
-	static hda_nid_t pin_idxs[] = { 0xff, 0x23, 0x1d, 0x1e, 0x21 };
+	static const hda_nid_t pin_idxs[] = { 0xff, 0x23, 0x1d, 0x1e, 0x21 };
 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x18, pin_idxs,
 						ARRAY_SIZE(pin_idxs));
 }
@@ -3106,7 +2673,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec)
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list vt1709_loopbacks[] = {
+static const struct hda_amp_list vt1709_loopbacks[] = {
 	{ 0x18, HDA_INPUT, 1 },
 	{ 0x18, HDA_INPUT, 2 },
 	{ 0x18, HDA_INPUT, 3 },
@@ -3167,7 +2734,7 @@ static int patch_vt1709_10ch(struct hda_codec *codec)
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
-static struct hda_verb vt1709_6ch_volume_init_verbs[] = {
+static const struct hda_verb vt1709_6ch_volume_init_verbs[] = {
 	/*
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 */
@@ -3257,7 +2824,7 @@ static int patch_vt1709_6ch(struct hda_codec *codec)
 }
 
 /* capture mixer elements */
-static struct snd_kcontrol_new vt1708B_capture_mixer[] = {
+static const struct snd_kcontrol_new vt1708B_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
@@ -3279,7 +2846,7 @@ static struct snd_kcontrol_new vt1708B_capture_mixer[] = {
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
-static struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
+static const struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
 	/*
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 */
@@ -3314,7 +2881,7 @@ static struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
+static const struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
 	/*
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 */
@@ -3349,7 +2916,7 @@ static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb vt1708B_uniwill_init_verbs[] = {
+static const struct hda_verb vt1708B_uniwill_init_verbs[] = {
 	{0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
 	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
@@ -3373,7 +2940,7 @@ static int via_pcm_open_close(struct hda_pcm_stream *hinfo,
 	return 0;
 }
 
-static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
+static const struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 8,
@@ -3386,7 +2953,7 @@ static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
 	},
 };
 
-static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
+static const struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 4,
@@ -3398,7 +2965,7 @@ static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
 	},
 };
 
-static struct hda_pcm_stream vt1708B_pcm_analog_capture = {
+static const struct hda_pcm_stream vt1708B_pcm_analog_capture = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -3411,7 +2978,7 @@ static struct hda_pcm_stream vt1708B_pcm_analog_capture = {
 	},
 };
 
-static struct hda_pcm_stream vt1708B_pcm_digital_playback = {
+static const struct hda_pcm_stream vt1708B_pcm_digital_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -3424,7 +2991,7 @@ static struct hda_pcm_stream vt1708B_pcm_digital_playback = {
 	},
 };
 
-static struct hda_pcm_stream vt1708B_pcm_digital_capture = {
+static const struct hda_pcm_stream vt1708B_pcm_digital_capture = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -3447,16 +3014,16 @@ static int vt1708B_auto_fill_dac_nids(struct via_spec *spec,
 			/* config dac list */
 			switch (i) {
 			case AUTO_SEQ_FRONT:
-				spec->multiout.dac_nids[i] = 0x10;
+				spec->private_dac_nids[i] = 0x10;
 				break;
 			case AUTO_SEQ_CENLFE:
-				spec->multiout.dac_nids[i] = 0x24;
+				spec->private_dac_nids[i] = 0x24;
 				break;
 			case AUTO_SEQ_SURROUND:
-				spec->multiout.dac_nids[i] = 0x11;
+				spec->private_dac_nids[i] = 0x11;
 				break;
 			case AUTO_SEQ_SIDE:
-				spec->multiout.dac_nids[i] = 0x25;
+				spec->private_dac_nids[i] = 0x25;
 				break;
 			}
 		}
@@ -3588,7 +3155,7 @@ static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 static int vt1708B_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 {
-	static hda_nid_t pin_idxs[] = { 0xff, 0x1f, 0x1a, 0x1b, 0x1e };
+	static const hda_nid_t pin_idxs[] = { 0xff, 0x1f, 0x1a, 0x1b, 0x1e };
 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
 						ARRAY_SIZE(pin_idxs));
 }
@@ -3638,7 +3205,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec)
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list vt1708B_loopbacks[] = {
+static const struct hda_amp_list vt1708B_loopbacks[] = {
 	{ 0x16, HDA_INPUT, 1 },
 	{ 0x16, HDA_INPUT, 2 },
 	{ 0x16, HDA_INPUT, 3 },
@@ -3646,6 +3213,87 @@ static struct hda_amp_list vt1708B_loopbacks[] = {
 	{ } /* end */
 };
 #endif
+
+static void set_widgets_power_state_vt1708B(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	int imux_is_smixer;
+	unsigned int parm;
+	int is_8ch = 0;
+	if ((spec->codec_type != VT1708B_4CH) &&
+	    (codec->vendor_id != 0x11064397))
+		is_8ch = 1;
+
+	/* SW0 (17h) = stereo mixer */
+	imux_is_smixer =
+	(snd_hda_codec_read(codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00)
+	 == ((spec->codec_type == VT1708S) ? 5 : 0));
+	/* inputs */
+	/* PW 1/2/5 (1ah/1bh/1eh) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x1a, &parm);
+	set_pin_power_state(codec, 0x1b, &parm);
+	set_pin_power_state(codec, 0x1e, &parm);
+	if (imux_is_smixer)
+		parm = AC_PWRST_D0;
+	/* SW0 (17h), AIW 0/1 (13h/14h) */
+	snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* outputs */
+	/* PW0 (19h), SW1 (18h), AOW1 (11h) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x19, &parm);
+	if (spec->smart51_enabled)
+		set_pin_power_state(codec, 0x1b, &parm);
+	snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* PW6 (22h), SW2 (26h), AOW2 (24h) */
+	if (is_8ch) {
+		parm = AC_PWRST_D3;
+		set_pin_power_state(codec, 0x22, &parm);
+		if (spec->smart51_enabled)
+			set_pin_power_state(codec, 0x1a, &parm);
+		snd_hda_codec_write(codec, 0x26, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x24, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	} else if (codec->vendor_id == 0x11064397) {
+		/* PW7(23h), SW2(27h), AOW2(25h) */
+		parm = AC_PWRST_D3;
+		set_pin_power_state(codec, 0x23, &parm);
+		if (spec->smart51_enabled)
+			set_pin_power_state(codec, 0x1a, &parm);
+		snd_hda_codec_write(codec, 0x27, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x25, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	}
+
+	/* PW 3/4/7 (1ch/1dh/23h) */
+	parm = AC_PWRST_D3;
+	/* force to D0 for internal Speaker */
+	set_pin_power_state(codec, 0x1c, &parm);
+	set_pin_power_state(codec, 0x1d, &parm);
+	if (is_8ch)
+		set_pin_power_state(codec, 0x23, &parm);
+
+	/* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */
+	snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
+			    imux_is_smixer ? AC_PWRST_D0 : parm);
+	snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
+	if (is_8ch) {
+		snd_hda_codec_write(codec, 0x25, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x27, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	} else if (codec->vendor_id == 0x11064397 && spec->hp_independent_mode)
+		snd_hda_codec_write(codec, 0x25, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+}
+
 static int patch_vt1708S(struct hda_codec *codec);
 static int patch_vt1708B_8ch(struct hda_codec *codec)
 {
@@ -3696,6 +3344,8 @@ static int patch_vt1708B_8ch(struct hda_codec *codec)
 	spec->loopback.amplist = vt1708B_loopbacks;
 #endif
 
+	spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
+
 	return 0;
 }
 
@@ -3746,13 +3396,15 @@ static int patch_vt1708B_4ch(struct hda_codec *codec)
 	spec->loopback.amplist = vt1708B_loopbacks;
 #endif
 
+	spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
+
 	return 0;
 }
 
 /* Patch for VT1708S */
 
 /* capture mixer elements */
-static struct snd_kcontrol_new vt1708S_capture_mixer[] = {
+static const struct snd_kcontrol_new vt1708S_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
@@ -3775,7 +3427,7 @@ static struct snd_kcontrol_new vt1708S_capture_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb vt1708S_volume_init_verbs[] = {
+static const struct hda_verb vt1708S_volume_init_verbs[] = {
 	/* Unmute ADC0-1 and set the default input to mic-in */
 	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -3801,7 +3453,7 @@ static struct hda_verb vt1708S_volume_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb vt1708S_uniwill_init_verbs[] = {
+static const struct hda_verb vt1708S_uniwill_init_verbs[] = {
 	{0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
 	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
@@ -3814,7 +3466,19 @@ static struct hda_verb vt1708S_uniwill_init_verbs[] = {
 	{ }
 };
 
-static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
+static const struct hda_verb vt1705_uniwill_init_verbs[] = {
+	{0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
+	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
+	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+	{0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+	{0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+	{0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+	{0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+	{ }
+};
+
+static const struct hda_pcm_stream vt1708S_pcm_analog_playback = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 8,
@@ -3827,7 +3491,20 @@ static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
 	},
 };
 
-static struct hda_pcm_stream vt1708S_pcm_analog_capture = {
+static const struct hda_pcm_stream vt1705_pcm_analog_playback = {
+	.substreams = 2,
+	.channels_min = 2,
+	.channels_max = 6,
+	.nid = 0x10, /* NID to query formats and rates */
+	.ops = {
+		.open = via_playback_pcm_open,
+		.prepare = via_playback_multi_pcm_prepare,
+		.cleanup = via_playback_multi_pcm_cleanup,
+		.close = via_pcm_open_close
+	},
+};
+
+static const struct hda_pcm_stream vt1708S_pcm_analog_capture = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -3840,7 +3517,7 @@ static struct hda_pcm_stream vt1708S_pcm_analog_capture = {
 	},
 };
 
-static struct hda_pcm_stream vt1708S_pcm_digital_playback = {
+static const struct hda_pcm_stream vt1708S_pcm_digital_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -3870,16 +3547,19 @@ static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
 			/* config dac list */
 			switch (i) {
 			case AUTO_SEQ_FRONT:
-				spec->multiout.dac_nids[i] = 0x10;
+				spec->private_dac_nids[i] = 0x10;
 				break;
 			case AUTO_SEQ_CENLFE:
-				spec->multiout.dac_nids[i] = 0x24;
+				if (spec->codec->vendor_id == 0x11064397)
+					spec->private_dac_nids[i] = 0x25;
+				else
+					spec->private_dac_nids[i] = 0x24;
 				break;
 			case AUTO_SEQ_SURROUND:
-				spec->multiout.dac_nids[i] = 0x11;
+				spec->private_dac_nids[i] = 0x11;
 				break;
 			case AUTO_SEQ_SIDE:
-				spec->multiout.dac_nids[i] = 0x25;
+				spec->private_dac_nids[i] = 0x25;
 				break;
 			}
 		}
@@ -3888,23 +3568,29 @@ static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
 	/* for Smart 5.1, line/mic inputs double as output pins */
 	if (cfg->line_outs == 1) {
 		spec->multiout.num_dacs = 3;
-		spec->multiout.dac_nids[AUTO_SEQ_SURROUND] = 0x11;
-		spec->multiout.dac_nids[AUTO_SEQ_CENLFE] = 0x24;
+		spec->private_dac_nids[AUTO_SEQ_SURROUND] = 0x11;
+		if (spec->codec->vendor_id == 0x11064397)
+			spec->private_dac_nids[AUTO_SEQ_CENLFE] = 0x25;
+		else
+			spec->private_dac_nids[AUTO_SEQ_CENLFE] = 0x24;
 	}
 
 	return 0;
 }
 
 /* add playback controls from the parsed DAC table */
-static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
+static int vt1708S_auto_create_multi_out_ctls(struct hda_codec *codec,
 					     const struct auto_pin_cfg *cfg)
 {
+	struct via_spec *spec = codec->spec;
 	char name[32];
 	static const char * const chname[4] = {
 		"Front", "Surround", "C/LFE", "Side"
 	};
-	hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25};
-	hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27};
+	hda_nid_t nid_vols[2][4] = { {0x10, 0x11, 0x24, 0x25},
+				     {0x10, 0x11, 0x25, 0} };
+	hda_nid_t nid_mutes[2][4] = { {0x1C, 0x18, 0x26, 0x27},
+				      {0x1C, 0x18, 0x27, 0} };
 	hda_nid_t nid, nid_vol, nid_mute;
 	int i, err;
 
@@ -3915,8 +3601,15 @@ static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
 		if (!nid && i > AUTO_SEQ_CENLFE)
 			continue;
 
-		nid_vol = nid_vols[i];
-		nid_mute = nid_mutes[i];
+		if (codec->vendor_id == 0x11064397) {
+			nid_vol = nid_vols[1][i];
+			nid_mute = nid_mutes[1][i];
+		} else {
+			nid_vol = nid_vols[0][i];
+			nid_mute = nid_mutes[0][i];
+		}
+		if (!nid_vol && !nid_mute)
+			continue;
 
 		if (i == AUTO_SEQ_CENLFE) {
 			/* Center/LFE */
@@ -4026,7 +3719,7 @@ static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 static int vt1708S_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 {
-	static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
+	static const hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
 						ARRAY_SIZE(pin_idxs));
 }
@@ -4070,7 +3763,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
 	if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
 		return 0; /* can't find valid BIOS pin config */
 
-	err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg);
+	err = vt1708S_auto_create_multi_out_ctls(codec, &spec->autocfg);
 	if (err < 0)
 		return err;
 	err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
@@ -4097,7 +3790,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list vt1708S_loopbacks[] = {
+static const struct hda_amp_list vt1708S_loopbacks[] = {
 	{ 0x16, HDA_INPUT, 1 },
 	{ 0x16, HDA_INPUT, 2 },
 	{ 0x16, HDA_INPUT, 3 },
@@ -4137,17 +3830,29 @@ static int patch_vt1708S(struct hda_codec *codec)
 	}
 
 	spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs;
-	spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs;
+	if (codec->vendor_id == 0x11064397)
+		spec->init_verbs[spec->num_iverbs++] =
+			vt1705_uniwill_init_verbs;
+	else
+		spec->init_verbs[spec->num_iverbs++] =
+			vt1708S_uniwill_init_verbs;
 
 	if (codec->vendor_id == 0x11060440)
 		spec->stream_name_analog = "VT1818S Analog";
+	else if (codec->vendor_id == 0x11064397)
+		spec->stream_name_analog = "VT1705 Analog";
 	else
 		spec->stream_name_analog = "VT1708S Analog";
-	spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
+	if (codec->vendor_id == 0x11064397)
+		spec->stream_analog_playback = &vt1705_pcm_analog_playback;
+	else
+		spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
 	spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
 
 	if (codec->vendor_id == 0x11060440)
 		spec->stream_name_digital = "VT1818S Digital";
+	else if (codec->vendor_id == 0x11064397)
+		spec->stream_name_digital = "VT1705 Digital";
 	else
 		spec->stream_name_digital = "VT1708S Digital";
 	spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
@@ -4185,13 +3890,22 @@ static int patch_vt1708S(struct hda_codec *codec)
 		spec->stream_name_analog = "VT1818S Analog";
 		spec->stream_name_digital = "VT1818S Digital";
 	}
+	/* correct names for VT1705 */
+	if (codec->vendor_id == 0x11064397)	{
+		kfree(codec->chip_name);
+		codec->chip_name = kstrdup("VT1705", GFP_KERNEL);
+		snprintf(codec->bus->card->mixername,
+			 sizeof(codec->bus->card->mixername),
+			 "%s %s", codec->vendor_name, codec->chip_name);
+	}
+	spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
 	return 0;
 }
 
 /* Patch for VT1702 */
 
 /* capture mixer elements */
-static struct snd_kcontrol_new vt1702_capture_mixer[] = {
+static const struct snd_kcontrol_new vt1702_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT),
@@ -4215,7 +3929,7 @@ static struct snd_kcontrol_new vt1702_capture_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb vt1702_volume_init_verbs[] = {
+static const struct hda_verb vt1702_volume_init_verbs[] = {
 	/*
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 */
@@ -4246,7 +3960,7 @@ static struct hda_verb vt1702_volume_init_verbs[] = {
 	{ }
 };
 
-static struct hda_verb vt1702_uniwill_init_verbs[] = {
+static const struct hda_verb vt1702_uniwill_init_verbs[] = {
 	{0x17, AC_VERB_SET_UNSOLICITED_ENABLE,
 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
 	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
@@ -4256,7 +3970,7 @@ static struct hda_verb vt1702_uniwill_init_verbs[] = {
 	{ }
 };
 
-static struct hda_pcm_stream vt1702_pcm_analog_playback = {
+static const struct hda_pcm_stream vt1702_pcm_analog_playback = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -4269,7 +3983,7 @@ static struct hda_pcm_stream vt1702_pcm_analog_playback = {
 	},
 };
 
-static struct hda_pcm_stream vt1702_pcm_analog_capture = {
+static const struct hda_pcm_stream vt1702_pcm_analog_capture = {
 	.substreams = 3,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -4282,7 +3996,7 @@ static struct hda_pcm_stream vt1702_pcm_analog_capture = {
 	},
 };
 
-static struct hda_pcm_stream vt1702_pcm_digital_playback = {
+static const struct hda_pcm_stream vt1702_pcm_digital_playback = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -4304,7 +4018,7 @@ static int vt1702_auto_fill_dac_nids(struct via_spec *spec,
 
 	if (cfg->line_out_pins[0]) {
 		/* config dac list */
-		spec->multiout.dac_nids[0] = 0x10;
+		spec->private_dac_nids[0] = 0x10;
 	}
 
 	return 0;
@@ -4382,7 +4096,7 @@ static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 static int vt1702_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 {
-	static hda_nid_t pin_idxs[] = { 0x14, 0x15, 0x18, 0xff };
+	static const hda_nid_t pin_idxs[] = { 0x14, 0x15, 0x18, 0xff };
 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x1a, pin_idxs,
 						ARRAY_SIZE(pin_idxs));
 }
@@ -4433,7 +4147,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec)
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list vt1702_loopbacks[] = {
+static const struct hda_amp_list vt1702_loopbacks[] = {
 	{ 0x1A, HDA_INPUT, 1 },
 	{ 0x1A, HDA_INPUT, 2 },
 	{ 0x1A, HDA_INPUT, 3 },
@@ -4442,6 +4156,37 @@ static struct hda_amp_list vt1702_loopbacks[] = {
 };
 #endif
 
+static void set_widgets_power_state_vt1702(struct hda_codec *codec)
+{
+	int imux_is_smixer =
+	snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
+	unsigned int parm;
+	/* inputs */
+	/* PW 1/2/5 (14h/15h/18h) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x14, &parm);
+	set_pin_power_state(codec, 0x15, &parm);
+	set_pin_power_state(codec, 0x18, &parm);
+	if (imux_is_smixer)
+		parm = AC_PWRST_D0; /* SW0 (13h) = stereo mixer (idx 3) */
+	/* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */
+	snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* outputs */
+	/* PW 3/4 (16h/17h) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x17, &parm);
+	set_pin_power_state(codec, 0x16, &parm);
+	/* MW0 (1ah), AOW 0/1 (10h/1dh) */
+	snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
+			    imux_is_smixer ? AC_PWRST_D0 : parm);
+	snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm);
+}
+
 static int patch_vt1702(struct hda_codec *codec)
 {
 	struct via_spec *spec;
@@ -4488,13 +4233,14 @@ static int patch_vt1702(struct hda_codec *codec)
 	spec->loopback.amplist = vt1702_loopbacks;
 #endif
 
+	spec->set_widgets_power_state =  set_widgets_power_state_vt1702;
 	return 0;
 }
 
 /* Patch for VT1718S */
 
 /* capture mixer elements */
-static struct snd_kcontrol_new vt1718S_capture_mixer[] = {
+static const struct snd_kcontrol_new vt1718S_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
@@ -4516,14 +4262,15 @@ static struct snd_kcontrol_new vt1718S_capture_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb vt1718S_volume_init_verbs[] = {
+static const struct hda_verb vt1718S_volume_init_verbs[] = {
 	/*
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 */
 	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 
-
+	/* Enable MW0 adjust Gain 5 */
+	{0x1, 0xfb2, 0x10},
 	/* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
 	 * mixer widget
 	 */
@@ -4532,7 +4279,7 @@ static struct hda_verb vt1718S_volume_init_verbs[] = {
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
 
 	/* Setup default input of Front HP to MW9 */
 	{0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
@@ -4563,7 +4310,7 @@ static struct hda_verb vt1718S_volume_init_verbs[] = {
 };
 
 
-static struct hda_verb vt1718S_uniwill_init_verbs[] = {
+static const struct hda_verb vt1718S_uniwill_init_verbs[] = {
 	{0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
 	{0x24, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
@@ -4576,7 +4323,7 @@ static struct hda_verb vt1718S_uniwill_init_verbs[] = {
 	{ }
 };
 
-static struct hda_pcm_stream vt1718S_pcm_analog_playback = {
+static const struct hda_pcm_stream vt1718S_pcm_analog_playback = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 10,
@@ -4589,7 +4336,7 @@ static struct hda_pcm_stream vt1718S_pcm_analog_playback = {
 	},
 };
 
-static struct hda_pcm_stream vt1718S_pcm_analog_capture = {
+static const struct hda_pcm_stream vt1718S_pcm_analog_capture = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -4602,7 +4349,7 @@ static struct hda_pcm_stream vt1718S_pcm_analog_capture = {
 	},
 };
 
-static struct hda_pcm_stream vt1718S_pcm_digital_playback = {
+static const struct hda_pcm_stream vt1718S_pcm_digital_playback = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -4615,7 +4362,7 @@ static struct hda_pcm_stream vt1718S_pcm_digital_playback = {
 	},
 };
 
-static struct hda_pcm_stream vt1718S_pcm_digital_capture = {
+static const struct hda_pcm_stream vt1718S_pcm_digital_capture = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -4638,16 +4385,16 @@ static int vt1718S_auto_fill_dac_nids(struct via_spec *spec,
 			/* config dac list */
 			switch (i) {
 			case AUTO_SEQ_FRONT:
-				spec->multiout.dac_nids[i] = 0x8;
+				spec->private_dac_nids[i] = 0x8;
 				break;
 			case AUTO_SEQ_CENLFE:
-				spec->multiout.dac_nids[i] = 0xa;
+				spec->private_dac_nids[i] = 0xa;
 				break;
 			case AUTO_SEQ_SURROUND:
-				spec->multiout.dac_nids[i] = 0x9;
+				spec->private_dac_nids[i] = 0x9;
 				break;
 			case AUTO_SEQ_SIDE:
-				spec->multiout.dac_nids[i] = 0xb;
+				spec->private_dac_nids[i] = 0xb;
 				break;
 			}
 		}
@@ -4769,7 +4516,7 @@ static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 static int vt1718S_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 {
-	static hda_nid_t pin_idxs[] = { 0x2c, 0x2b, 0x2a, 0x29, 0, 0xff };
+	static const hda_nid_t pin_idxs[] = { 0x2c, 0x2b, 0x2a, 0x29, 0, 0xff };
 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
 						ARRAY_SIZE(pin_idxs));
 }
@@ -4820,7 +4567,7 @@ static int vt1718S_parse_auto_config(struct hda_codec *codec)
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list vt1718S_loopbacks[] = {
+static const struct hda_amp_list vt1718S_loopbacks[] = {
 	{ 0x21, HDA_INPUT, 1 },
 	{ 0x21, HDA_INPUT, 2 },
 	{ 0x21, HDA_INPUT, 3 },
@@ -4829,6 +4576,72 @@ static struct hda_amp_list vt1718S_loopbacks[] = {
 };
 #endif
 
+static void set_widgets_power_state_vt1718S(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	int imux_is_smixer;
+	unsigned int parm;
+	/* MUX6 (1eh) = stereo mixer */
+	imux_is_smixer =
+	snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
+	/* inputs */
+	/* PW 5/6/7 (29h/2ah/2bh) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x29, &parm);
+	set_pin_power_state(codec, 0x2a, &parm);
+	set_pin_power_state(codec, 0x2b, &parm);
+	if (imux_is_smixer)
+		parm = AC_PWRST_D0;
+	/* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */
+	snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* outputs */
+	/* PW3 (27h), MW2 (1ah), AOW3 (bh) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x27, &parm);
+	snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* PW2 (26h), AOW2 (ah) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x26, &parm);
+	if (spec->smart51_enabled)
+		set_pin_power_state(codec, 0x2b, &parm);
+	snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* PW0 (24h), AOW0 (8h) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x24, &parm);
+	if (!spec->hp_independent_mode) /* check for redirected HP */
+		set_pin_power_state(codec, 0x28, &parm);
+	snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm);
+	/* MW9 (21h), Mw2 (1ah), AOW0 (8h) */
+	snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE,
+			    imux_is_smixer ? AC_PWRST_D0 : parm);
+
+	/* PW1 (25h), AOW1 (9h) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x25, &parm);
+	if (spec->smart51_enabled)
+		set_pin_power_state(codec, 0x2a, &parm);
+	snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	if (spec->hp_independent_mode) {
+		/* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */
+		parm = AC_PWRST_D3;
+		set_pin_power_state(codec, 0x28, &parm);
+		snd_hda_codec_write(codec, 0x1b, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x34, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0xc, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	}
+}
+
 static int patch_vt1718S(struct hda_codec *codec)
 {
 	struct via_spec *spec;
@@ -4890,6 +4703,8 @@ static int patch_vt1718S(struct hda_codec *codec)
 	spec->loopback.amplist = vt1718S_loopbacks;
 #endif
 
+	spec->set_widgets_power_state =  set_widgets_power_state_vt1718S;
+
 	return 0;
 }
 
@@ -4929,13 +4744,12 @@ static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol,
 	snd_hda_codec_write(codec, 0x26, 0,
 					       AC_VERB_SET_CONNECT_SEL, index);
 	spec->dmic_enabled = index;
-	set_jack_power_state(codec);
-
+	set_widgets_power_state(codec);
 	return 1;
 }
 
 /* capture mixer elements */
-static struct snd_kcontrol_new vt1716S_capture_mixer[] = {
+static const struct snd_kcontrol_new vt1716S_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
@@ -4954,7 +4768,7 @@ static struct snd_kcontrol_new vt1716S_capture_mixer[] = {
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
+static const struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
 	HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT),
 	{
 	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -4970,12 +4784,12 @@ static struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
 
 
 /* mono-out mixer elements */
-static struct snd_kcontrol_new vt1716S_mono_out_mixer[] = {
+static const struct snd_kcontrol_new vt1716S_mono_out_mixer[] = {
 	HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT),
 	{ } /* end */
 };
 
-static struct hda_verb vt1716S_volume_init_verbs[] = {
+static const struct hda_verb vt1716S_volume_init_verbs[] = {
 	/*
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 */
@@ -5024,7 +4838,7 @@ static struct hda_verb vt1716S_volume_init_verbs[] = {
 };
 
 
-static struct hda_verb vt1716S_uniwill_init_verbs[] = {
+static const struct hda_verb vt1716S_uniwill_init_verbs[] = {
 	{0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
 	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
@@ -5037,7 +4851,7 @@ static struct hda_verb vt1716S_uniwill_init_verbs[] = {
 	{ }
 };
 
-static struct hda_pcm_stream vt1716S_pcm_analog_playback = {
+static const struct hda_pcm_stream vt1716S_pcm_analog_playback = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 6,
@@ -5050,7 +4864,7 @@ static struct hda_pcm_stream vt1716S_pcm_analog_playback = {
 	},
 };
 
-static struct hda_pcm_stream vt1716S_pcm_analog_capture = {
+static const struct hda_pcm_stream vt1716S_pcm_analog_capture = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -5063,7 +4877,7 @@ static struct hda_pcm_stream vt1716S_pcm_analog_capture = {
 	},
 };
 
-static struct hda_pcm_stream vt1716S_pcm_digital_playback = {
+static const struct hda_pcm_stream vt1716S_pcm_digital_playback = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -5092,13 +4906,13 @@ static int vt1716S_auto_fill_dac_nids(struct via_spec *spec,
 			/* config dac list */
 			switch (i) {
 			case AUTO_SEQ_FRONT:
-				spec->multiout.dac_nids[i] = 0x10;
+				spec->private_dac_nids[i] = 0x10;
 				break;
 			case AUTO_SEQ_CENLFE:
-				spec->multiout.dac_nids[i] = 0x25;
+				spec->private_dac_nids[i] = 0x25;
 				break;
 			case AUTO_SEQ_SURROUND:
-				spec->multiout.dac_nids[i] = 0x11;
+				spec->private_dac_nids[i] = 0x11;
 				break;
 			}
 		}
@@ -5233,7 +5047,7 @@ static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 static int vt1716S_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 {
-	static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
+	static const hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
 						ARRAY_SIZE(pin_idxs));
 }
@@ -5280,7 +5094,7 @@ static int vt1716S_parse_auto_config(struct hda_codec *codec)
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list vt1716S_loopbacks[] = {
+static const struct hda_amp_list vt1716S_loopbacks[] = {
 	{ 0x16, HDA_INPUT, 1 },
 	{ 0x16, HDA_INPUT, 2 },
 	{ 0x16, HDA_INPUT, 3 },
@@ -5289,6 +5103,99 @@ static struct hda_amp_list vt1716S_loopbacks[] = {
 };
 #endif
 
+static void set_widgets_power_state_vt1716S(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	int imux_is_smixer;
+	unsigned int parm;
+	unsigned int mono_out, present;
+	/* SW0 (17h) = stereo mixer */
+	imux_is_smixer =
+	(snd_hda_codec_read(codec, 0x17, 0,
+			    AC_VERB_GET_CONNECT_SEL, 0x00) ==  5);
+	/* inputs */
+	/* PW 1/2/5 (1ah/1bh/1eh) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x1a, &parm);
+	set_pin_power_state(codec, 0x1b, &parm);
+	set_pin_power_state(codec, 0x1e, &parm);
+	if (imux_is_smixer)
+		parm = AC_PWRST_D0;
+	/* SW0 (17h), AIW0(13h) */
+	snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x1e, &parm);
+	/* PW11 (22h) */
+	if (spec->dmic_enabled)
+		set_pin_power_state(codec, 0x22, &parm);
+	else
+		snd_hda_codec_write(codec, 0x22, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+
+	/* SW2(26h), AIW1(14h) */
+	snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* outputs */
+	/* PW0 (19h), SW1 (18h), AOW1 (11h) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x19, &parm);
+	/* Smart 5.1 PW2(1bh) */
+	if (spec->smart51_enabled)
+		set_pin_power_state(codec, 0x1b, &parm);
+	snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* PW7 (23h), SW3 (27h), AOW3 (25h) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x23, &parm);
+	/* Smart 5.1 PW1(1ah) */
+	if (spec->smart51_enabled)
+		set_pin_power_state(codec, 0x1a, &parm);
+	snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* Smart 5.1 PW5(1eh) */
+	if (spec->smart51_enabled)
+		set_pin_power_state(codec, 0x1e, &parm);
+	snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* Mono out */
+	/* SW4(28h)->MW1(29h)-> PW12 (2ah)*/
+	present = snd_hda_jack_detect(codec, 0x1c);
+
+	if (present)
+		mono_out = 0;
+	else {
+		present = snd_hda_jack_detect(codec, 0x1d);
+		if (!spec->hp_independent_mode && present)
+			mono_out = 0;
+		else
+			mono_out = 1;
+	}
+	parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3;
+	snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* PW 3/4 (1ch/1dh) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x1c, &parm);
+	set_pin_power_state(codec, 0x1d, &parm);
+	/* HP Independent Mode, power on AOW3 */
+	if (spec->hp_independent_mode)
+		snd_hda_codec_write(codec, 0x25, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+
+	/* force to D0 for internal Speaker */
+	/* MW0 (16h), AOW0 (10h) */
+	snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
+			    imux_is_smixer ? AC_PWRST_D0 : parm);
+	snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
+			    mono_out ? AC_PWRST_D0 : parm);
+}
+
 static int patch_vt1716S(struct hda_codec *codec)
 {
 	struct via_spec *spec;
@@ -5343,13 +5250,14 @@ static int patch_vt1716S(struct hda_codec *codec)
 	spec->loopback.amplist = vt1716S_loopbacks;
 #endif
 
+	spec->set_widgets_power_state = set_widgets_power_state_vt1716S;
 	return 0;
 }
 
 /* for vt2002P */
 
 /* capture mixer elements */
-static struct snd_kcontrol_new vt2002P_capture_mixer[] = {
+static const struct snd_kcontrol_new vt2002P_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
@@ -5372,7 +5280,11 @@ static struct snd_kcontrol_new vt2002P_capture_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb vt2002P_volume_init_verbs[] = {
+static const struct hda_verb vt2002P_volume_init_verbs[] = {
+	/* Class-D speaker related verbs */
+	{0x1, 0xfe0, 0x4},
+	{0x1, 0xfe9, 0x80},
+	{0x1, 0xfe2, 0x22},
 	/*
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 */
@@ -5423,9 +5335,60 @@ static struct hda_verb vt2002P_volume_init_verbs[] = {
 	{0x1, 0xfb8, 0x88},
 	{ }
 };
+static const struct hda_verb vt1802_volume_init_verbs[] = {
+	/*
+	 * Unmute ADC0-1 and set the default input to mic-in
+	 */
+	{0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+	/* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+	 * mixer widget
+	 */
+	/* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
+	/* MUX Indices: Mic = 0 */
+	{0x1e, AC_VERB_SET_CONNECT_SEL, 0},
+	{0x1f, AC_VERB_SET_CONNECT_SEL, 0},
+
+	/* PW9 Output enable */
+	{0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
+
+	/* Enable Boost Volume backdoor */
+	{0x1, 0xfb9, 0x24},
+
+	/* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+	/* set MUX0/1/4/8 = 0 (AOW0) */
+	{0x34, AC_VERB_SET_CONNECT_SEL, 0},
+	{0x35, AC_VERB_SET_CONNECT_SEL, 0},
+	{0x38, AC_VERB_SET_CONNECT_SEL, 0},
+	{0x3c, AC_VERB_SET_CONNECT_SEL, 0},
+
+	/* set PW0 index=0 (MW0) */
+	{0x24, AC_VERB_SET_CONNECT_SEL, 0},
+
+	/* Enable AOW0 to MW9 */
+	{0x1, 0xfb8, 0x88},
+	{ }
+};
 
 
-static struct hda_verb vt2002P_uniwill_init_verbs[] = {
+static const struct hda_verb vt2002P_uniwill_init_verbs[] = {
 	{0x25, AC_VERB_SET_UNSOLICITED_ENABLE,
 	 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
 	{0x26, AC_VERB_SET_UNSOLICITED_ENABLE,
@@ -5435,8 +5398,18 @@ static struct hda_verb vt2002P_uniwill_init_verbs[] = {
 	{0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
 	{ }
 };
+static const struct hda_verb vt1802_uniwill_init_verbs[] = {
+	{0x25, AC_VERB_SET_UNSOLICITED_ENABLE,
+	 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
+	{0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
+	 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
+	{0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+	{0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+	{0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+	{ }
+};
 
-static struct hda_pcm_stream vt2002P_pcm_analog_playback = {
+static const struct hda_pcm_stream vt2002P_pcm_analog_playback = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -5449,7 +5422,7 @@ static struct hda_pcm_stream vt2002P_pcm_analog_playback = {
 	},
 };
 
-static struct hda_pcm_stream vt2002P_pcm_analog_capture = {
+static const struct hda_pcm_stream vt2002P_pcm_analog_capture = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -5462,7 +5435,7 @@ static struct hda_pcm_stream vt2002P_pcm_analog_capture = {
 	},
 };
 
-static struct hda_pcm_stream vt2002P_pcm_digital_playback = {
+static const struct hda_pcm_stream vt2002P_pcm_digital_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -5482,7 +5455,7 @@ static int vt2002P_auto_fill_dac_nids(struct via_spec *spec,
 	spec->multiout.num_dacs = 1;
 	spec->multiout.dac_nids = spec->private_dac_nids;
 	if (cfg->line_out_pins[0])
-		spec->multiout.dac_nids[0] = 0x8;
+		spec->private_dac_nids[0] = 0x8;
 	return 0;
 }
 
@@ -5491,10 +5464,15 @@ static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec,
 					     const struct auto_pin_cfg *cfg)
 {
 	int err;
+	hda_nid_t sw_nid;
 
 	if (!cfg->line_out_pins[0])
 		return -1;
 
+	if (spec->codec_type == VT1802)
+		sw_nid = 0x28;
+	else
+		sw_nid = 0x26;
 
 	/* Line-Out: PortE */
 	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
@@ -5504,7 +5482,7 @@ static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec,
 		return err;
 	err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE,
 			      "Master Front Playback Switch",
-			      HDA_COMPOSE_AMP_VAL(0x26, 3, 0, HDA_OUTPUT));
+			      HDA_COMPOSE_AMP_VAL(sw_nid, 3, 0, HDA_OUTPUT));
 	if (err < 0)
 		return err;
 
@@ -5544,7 +5522,7 @@ static int vt2002P_auto_create_analog_input_ctls(struct hda_codec *codec,
 {
 	struct via_spec *spec = codec->spec;
 	struct hda_input_mux *imux = &spec->private_imux[0];
-	static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0xff };
+	static const hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0xff };
 	int err;
 
 	err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
@@ -5605,7 +5583,7 @@ static int vt2002P_parse_auto_config(struct hda_codec *codec)
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list vt2002P_loopbacks[] = {
+static const struct hda_amp_list vt2002P_loopbacks[] = {
 	{ 0x21, HDA_INPUT, 0 },
 	{ 0x21, HDA_INPUT, 1 },
 	{ 0x21, HDA_INPUT, 2 },
@@ -5613,6 +5591,116 @@ static struct hda_amp_list vt2002P_loopbacks[] = {
 };
 #endif
 
+static void set_widgets_power_state_vt2002P(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	int imux_is_smixer;
+	unsigned int parm;
+	unsigned int present;
+	/* MUX9 (1eh) = stereo mixer */
+	imux_is_smixer =
+	snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
+	/* inputs */
+	/* PW 5/6/7 (29h/2ah/2bh) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x29, &parm);
+	set_pin_power_state(codec, 0x2a, &parm);
+	set_pin_power_state(codec, 0x2b, &parm);
+	parm = AC_PWRST_D0;
+	/* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */
+	snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* outputs */
+	/* AOW0 (8h)*/
+	snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	if (spec->codec_type == VT1802) {
+		/* PW4 (28h), MW4 (18h), MUX4(38h) */
+		parm = AC_PWRST_D3;
+		set_pin_power_state(codec, 0x28, &parm);
+		snd_hda_codec_write(codec, 0x18, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x38, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	} else {
+		/* PW4 (26h), MW4 (1ch), MUX4(37h) */
+		parm = AC_PWRST_D3;
+		set_pin_power_state(codec, 0x26, &parm);
+		snd_hda_codec_write(codec, 0x1c, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x37, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	}
+
+	if (spec->codec_type == VT1802) {
+		/* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */
+		parm = AC_PWRST_D3;
+		set_pin_power_state(codec, 0x25, &parm);
+		snd_hda_codec_write(codec, 0x15, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x35, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	} else {
+		/* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */
+		parm = AC_PWRST_D3;
+		set_pin_power_state(codec, 0x25, &parm);
+		snd_hda_codec_write(codec, 0x19, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x35, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	}
+
+	if (spec->hp_independent_mode)
+		snd_hda_codec_write(codec, 0x9, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+	/* Class-D */
+	/* PW0 (24h), MW0(18h/14h), MUX0(34h) */
+	present = snd_hda_jack_detect(codec, 0x25);
+
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x24, &parm);
+	parm = present ? AC_PWRST_D3 : AC_PWRST_D0;
+	if (spec->codec_type == VT1802)
+		snd_hda_codec_write(codec, 0x14, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	else
+		snd_hda_codec_write(codec, 0x18, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* Mono Out */
+	present = snd_hda_jack_detect(codec, 0x26);
+
+	parm = present ? AC_PWRST_D3 : AC_PWRST_D0;
+	if (spec->codec_type == VT1802) {
+		/* PW15 (33h), MW8(1ch), MUX8(3ch) */
+		snd_hda_codec_write(codec, 0x33, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x1c, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x3c, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	} else {
+		/* PW15 (31h), MW8(17h), MUX8(3bh) */
+		snd_hda_codec_write(codec, 0x31, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x17, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x3b, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	}
+	/* MW9 (21h) */
+	if (imux_is_smixer || !is_aa_path_mute(codec))
+		snd_hda_codec_write(codec, 0x21, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+	else
+		snd_hda_codec_write(codec, 0x21, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+}
 
 /* patch for vt2002P */
 static int patch_vt2002P(struct hda_codec *codec)
@@ -5635,14 +5723,31 @@ static int patch_vt2002P(struct hda_codec *codec)
 		       "from BIOS.  Using genenic mode...\n");
 	}
 
-	spec->init_verbs[spec->num_iverbs++]  = vt2002P_volume_init_verbs;
-	spec->init_verbs[spec->num_iverbs++] = vt2002P_uniwill_init_verbs;
+	if (spec->codec_type == VT1802)
+		spec->init_verbs[spec->num_iverbs++]  =
+			vt1802_volume_init_verbs;
+	else
+		spec->init_verbs[spec->num_iverbs++]  =
+			vt2002P_volume_init_verbs;
+
+	if (spec->codec_type == VT1802)
+		spec->init_verbs[spec->num_iverbs++] =
+			vt1802_uniwill_init_verbs;
+	else
+		spec->init_verbs[spec->num_iverbs++] =
+			vt2002P_uniwill_init_verbs;
 
-	spec->stream_name_analog = "VT2002P Analog";
+	if (spec->codec_type == VT1802)
+		spec->stream_name_analog = "VT1802 Analog";
+	else
+		spec->stream_name_analog = "VT2002P Analog";
 	spec->stream_analog_playback = &vt2002P_pcm_analog_playback;
 	spec->stream_analog_capture = &vt2002P_pcm_analog_capture;
 
-	spec->stream_name_digital = "VT2002P Digital";
+	if (spec->codec_type == VT1802)
+		spec->stream_name_digital = "VT1802 Digital";
+	else
+		spec->stream_name_digital = "VT2002P Digital";
 	spec->stream_digital_playback = &vt2002P_pcm_digital_playback;
 
 	if (!spec->adc_nids && spec->input_mux) {
@@ -5664,13 +5769,14 @@ static int patch_vt2002P(struct hda_codec *codec)
 	spec->loopback.amplist = vt2002P_loopbacks;
 #endif
 
+	spec->set_widgets_power_state =  set_widgets_power_state_vt2002P;
 	return 0;
 }
 
 /* for vt1812 */
 
 /* capture mixer elements */
-static struct snd_kcontrol_new vt1812_capture_mixer[] = {
+static const struct snd_kcontrol_new vt1812_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
@@ -5692,7 +5798,7 @@ static struct snd_kcontrol_new vt1812_capture_mixer[] = {
 	{ } /* end */
 };
 
-static struct hda_verb vt1812_volume_init_verbs[] = {
+static const struct hda_verb vt1812_volume_init_verbs[] = {
 	/*
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 */
@@ -5745,7 +5851,7 @@ static struct hda_verb vt1812_volume_init_verbs[] = {
 };
 
 
-static struct hda_verb vt1812_uniwill_init_verbs[] = {
+static const struct hda_verb vt1812_uniwill_init_verbs[] = {
 	{0x33, AC_VERB_SET_UNSOLICITED_ENABLE,
 	 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
 	{0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT },
@@ -5757,7 +5863,7 @@ static struct hda_verb vt1812_uniwill_init_verbs[] = {
 	{ }
 };
 
-static struct hda_pcm_stream vt1812_pcm_analog_playback = {
+static const struct hda_pcm_stream vt1812_pcm_analog_playback = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -5770,7 +5876,7 @@ static struct hda_pcm_stream vt1812_pcm_analog_playback = {
 	},
 };
 
-static struct hda_pcm_stream vt1812_pcm_analog_capture = {
+static const struct hda_pcm_stream vt1812_pcm_analog_capture = {
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -5783,7 +5889,7 @@ static struct hda_pcm_stream vt1812_pcm_analog_capture = {
 	},
 };
 
-static struct hda_pcm_stream vt1812_pcm_digital_playback = {
+static const struct hda_pcm_stream vt1812_pcm_digital_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -5802,7 +5908,7 @@ static int vt1812_auto_fill_dac_nids(struct via_spec *spec,
 	spec->multiout.num_dacs = 1;
 	spec->multiout.dac_nids = spec->private_dac_nids;
 	if (cfg->line_out_pins[0])
-		spec->multiout.dac_nids[0] = 0x8;
+		spec->private_dac_nids[0] = 0x8;
 	return 0;
 }
 
@@ -5865,7 +5971,7 @@ static int vt1812_auto_create_analog_input_ctls(struct hda_codec *codec,
 {
 	struct via_spec *spec = codec->spec;
 	struct hda_input_mux *imux = &spec->private_imux[0];
-	static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0, 0, 0xff };
+	static const hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0, 0, 0xff };
 	int err;
 
 	err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
@@ -5927,7 +6033,7 @@ static int vt1812_parse_auto_config(struct hda_codec *codec)
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list vt1812_loopbacks[] = {
+static const struct hda_amp_list vt1812_loopbacks[] = {
 	{ 0x21, HDA_INPUT, 0 },
 	{ 0x21, HDA_INPUT, 1 },
 	{ 0x21, HDA_INPUT, 2 },
@@ -5935,6 +6041,97 @@ static struct hda_amp_list vt1812_loopbacks[] = {
 };
 #endif
 
+static void set_widgets_power_state_vt1812(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	int imux_is_smixer =
+	snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
+	unsigned int parm;
+	unsigned int present;
+	/* MUX10 (1eh) = stereo mixer */
+	imux_is_smixer =
+	snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
+	/* inputs */
+	/* PW 5/6/7 (29h/2ah/2bh) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x29, &parm);
+	set_pin_power_state(codec, 0x2a, &parm);
+	set_pin_power_state(codec, 0x2b, &parm);
+	parm = AC_PWRST_D0;
+	/* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */
+	snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* outputs */
+	/* AOW0 (8h)*/
+	snd_hda_codec_write(codec, 0x8, 0,
+			    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+	/* PW4 (28h), MW4 (18h), MUX4(38h) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x28, &parm);
+	snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x38, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x25, &parm);
+	snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x35, 0, AC_VERB_SET_POWER_STATE, parm);
+	if (spec->hp_independent_mode)
+		snd_hda_codec_write(codec, 0x9, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+	/* Internal Speaker */
+	/* PW0 (24h), MW0(14h), MUX0(34h) */
+	present = snd_hda_jack_detect(codec, 0x25);
+
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x24, &parm);
+	if (present) {
+		snd_hda_codec_write(codec, 0x14, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+		snd_hda_codec_write(codec, 0x34, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+	} else {
+		snd_hda_codec_write(codec, 0x14, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+		snd_hda_codec_write(codec, 0x34, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+	}
+
+
+	/* Mono Out */
+	/* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */
+	present = snd_hda_jack_detect(codec, 0x28);
+
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x31, &parm);
+	if (present) {
+		snd_hda_codec_write(codec, 0x1c, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+		snd_hda_codec_write(codec, 0x3c, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+		snd_hda_codec_write(codec, 0x3e, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+	} else {
+		snd_hda_codec_write(codec, 0x1c, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+		snd_hda_codec_write(codec, 0x3c, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+		snd_hda_codec_write(codec, 0x3e, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+	}
+
+	/* PW15 (33h), MW15 (1dh), MUX15(3dh) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x33, &parm);
+	snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x3d, 0, AC_VERB_SET_POWER_STATE, parm);
+
+}
 
 /* patch for vt1812 */
 static int patch_vt1812(struct hda_codec *codec)
@@ -5988,13 +6185,14 @@ static int patch_vt1812(struct hda_codec *codec)
 	spec->loopback.amplist = vt1812_loopbacks;
 #endif
 
+	spec->set_widgets_power_state =  set_widgets_power_state_vt1812;
 	return 0;
 }
 
 /*
  * patch entries
  */
-static struct hda_codec_preset snd_hda_preset_via[] = {
+static const struct hda_codec_preset snd_hda_preset_via[] = {
 	{ .id = 0x11061708, .name = "VT1708", .patch = patch_vt1708},
 	{ .id = 0x11061709, .name = "VT1708", .patch = patch_vt1708},
 	{ .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708},
@@ -6039,7 +6237,7 @@ static struct hda_codec_preset snd_hda_preset_via[] = {
 	  .patch = patch_vt1708S},
 	{ .id = 0x11063397, .name = "VT1708S",
 	  .patch = patch_vt1708S},
-	{ .id = 0x11064397, .name = "VT1708S",
+	{ .id = 0x11064397, .name = "VT1705",
 	  .patch = patch_vt1708S},
 	{ .id = 0x11065397, .name = "VT1708S",
 	  .patch = patch_vt1708S},
@@ -6080,6 +6278,10 @@ static struct hda_codec_preset snd_hda_preset_via[] = {
 	{ .id = 0x11060448, .name = "VT1812", .patch = patch_vt1812},
 	{ .id = 0x11060440, .name = "VT1818S",
 	  .patch = patch_vt1708S},
+	{ .id = 0x11060446, .name = "VT1802",
+		.patch = patch_vt2002P},
+	{ .id = 0x11068446, .name = "VT1802",
+		.patch = patch_vt2002P},
 	{} /* terminator */
 };
 
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index 27709f0cd2a6..f3353b49c785 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -235,8 +235,8 @@ static DEFINE_PCI_DEVICE_TABLE(snd_intel8x0m_ids) = {
 	{ PCI_VDEVICE(NVIDIA, 0x0069), DEVICE_NFORCE }, /* NFORCE2 */
 	{ PCI_VDEVICE(NVIDIA, 0x0089), DEVICE_NFORCE }, /* NFORCE2s */
 	{ PCI_VDEVICE(NVIDIA, 0x00d9), DEVICE_NFORCE }, /* NFORCE3 */
+	{ PCI_VDEVICE(AMD, 0x746e), DEVICE_INTEL },	/* AMD8111 */
 #if 0
-	{ PCI_VDEVICE(AMD, 0x746d), DEVICE_INTEL },	/* AMD8111 */
 	{ PCI_VDEVICE(AL, 0x5455), DEVICE_ALI },   /* Ali5455 */
 #endif
 	{ 0, }
@@ -1261,9 +1261,9 @@ static struct shortname_table {
 	{ PCI_DEVICE_ID_NVIDIA_MCP2_MODEM, "NVidia nForce2" },
 	{ PCI_DEVICE_ID_NVIDIA_MCP2S_MODEM, "NVidia nForce2s" },
 	{ PCI_DEVICE_ID_NVIDIA_MCP3_MODEM, "NVidia nForce3" },
+	{ 0x746e, "AMD AMD8111" },
 #if 0
 	{ 0x5455, "ALi M5455" },
-	{ 0x746d, "AMD AMD8111" },
 #endif
 	{ 0 },
 };
diff --git a/sound/pci/lola/Makefile b/sound/pci/lola/Makefile
new file mode 100644
index 000000000000..8178a2a59d00
--- /dev/null
+++ b/sound/pci/lola/Makefile
@@ -0,0 +1,4 @@
+snd-lola-y := lola.o lola_pcm.o lola_clock.o lola_mixer.o
+snd-lola-$(CONFIG_SND_DEBUG) += lola_proc.o
+
+obj-$(CONFIG_SND_LOLA) += snd-lola.o
diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c
new file mode 100644
index 000000000000..34b24286d279
--- /dev/null
+++ b/sound/pci/lola/lola.c
@@ -0,0 +1,791 @@
+/*
+ *  Support for Digigram Lola PCI-e boards
+ *
+ *  Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
+ *
+ *  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, write to the Free Software Foundation, Inc., 59
+ *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include "lola.h"
+
+/* Standard options */
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for Digigram Lola driver.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for Digigram Lola driver.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable Digigram Lola driver.");
+
+/* Lola-specific options */
+
+/* for instance use always max granularity which is compatible
+ * with all sample rates
+ */
+static int granularity[SNDRV_CARDS] = {
+	[0 ... (SNDRV_CARDS - 1)] = LOLA_GRANULARITY_MAX
+};
+
+/* below a sample_rate of 16kHz the analogue audio quality is NOT excellent */
+static int sample_rate_min[SNDRV_CARDS] = {
+	[0 ... (SNDRV_CARDS - 1) ] = 16000
+};
+
+module_param_array(granularity, int, NULL, 0444);
+MODULE_PARM_DESC(granularity, "Granularity value");
+module_param_array(sample_rate_min, int, NULL, 0444);
+MODULE_PARM_DESC(sample_rate_min, "Minimal sample rate");
+
+/*
+ */
+
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Digigram, Lola}}");
+MODULE_DESCRIPTION("Digigram Lola driver");
+MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
+
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+static int debug;
+module_param(debug, int, 0644);
+#define verbose_debug(fmt, args...)			\
+	do { if (debug > 1) printk(KERN_DEBUG SFX fmt, ##args); } while (0)
+#else
+#define verbose_debug(fmt, args...)
+#endif
+
+/*
+ * pseudo-codec read/write via CORB/RIRB
+ */
+
+static int corb_send_verb(struct lola *chip, unsigned int nid,
+			  unsigned int verb, unsigned int data,
+			  unsigned int extdata)
+{
+	unsigned long flags;
+	int ret = -EIO;
+
+	chip->last_cmd_nid = nid;
+	chip->last_verb = verb;
+	chip->last_data = data;
+	chip->last_extdata = extdata;
+	data |= (nid << 20) | (verb << 8);
+
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	if (chip->rirb.cmds < LOLA_CORB_ENTRIES - 1) {
+		unsigned int wp = chip->corb.wp + 1;
+		wp %= LOLA_CORB_ENTRIES;
+		chip->corb.wp = wp;
+		chip->corb.buf[wp * 2] = cpu_to_le32(data);
+		chip->corb.buf[wp * 2 + 1] = cpu_to_le32(extdata);
+		lola_writew(chip, BAR0, CORBWP, wp);
+		chip->rirb.cmds++;
+		smp_wmb();
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	return ret;
+}
+
+static void lola_queue_unsol_event(struct lola *chip, unsigned int res,
+				   unsigned int res_ex)
+{
+	lola_update_ext_clock_freq(chip, res);
+}
+
+/* retrieve RIRB entry - called from interrupt handler */
+static void lola_update_rirb(struct lola *chip)
+{
+	unsigned int rp, wp;
+	u32 res, res_ex;
+
+	wp = lola_readw(chip, BAR0, RIRBWP);
+	if (wp == chip->rirb.wp)
+		return;
+	chip->rirb.wp = wp;
+
+	while (chip->rirb.rp != wp) {
+		chip->rirb.rp++;
+		chip->rirb.rp %= LOLA_CORB_ENTRIES;
+
+		rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */
+		res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]);
+		res = le32_to_cpu(chip->rirb.buf[rp]);
+		if (res_ex & LOLA_RIRB_EX_UNSOL_EV)
+			lola_queue_unsol_event(chip, res, res_ex);
+		else if (chip->rirb.cmds) {
+			chip->res = res;
+			chip->res_ex = res_ex;
+			smp_wmb();
+			chip->rirb.cmds--;
+		}
+	}
+}
+
+static int rirb_get_response(struct lola *chip, unsigned int *val,
+			     unsigned int *extval)
+{
+	unsigned long timeout;
+
+ again:
+	timeout = jiffies + msecs_to_jiffies(1000);
+	for (;;) {
+		if (chip->polling_mode) {
+			spin_lock_irq(&chip->reg_lock);
+			lola_update_rirb(chip);
+			spin_unlock_irq(&chip->reg_lock);
+		}
+		if (!chip->rirb.cmds) {
+			*val = chip->res;
+			if (extval)
+				*extval = chip->res_ex;
+			verbose_debug("get_response: %x, %x\n",
+				      chip->res, chip->res_ex);
+			if (chip->res_ex & LOLA_RIRB_EX_ERROR) {
+				printk(KERN_WARNING SFX "RIRB ERROR: "
+				       "NID=%x, verb=%x, data=%x, ext=%x\n",
+				       chip->last_cmd_nid,
+				       chip->last_verb, chip->last_data,
+				       chip->last_extdata);
+				return -EIO;
+			}
+			return 0;
+		}
+		if (time_after(jiffies, timeout))
+			break;
+		udelay(20);
+		cond_resched();
+	}
+	printk(KERN_WARNING SFX "RIRB response error\n");
+	if (!chip->polling_mode) {
+		printk(KERN_WARNING SFX "switching to polling mode\n");
+		chip->polling_mode = 1;
+		goto again;
+	}
+	return -EIO;
+}
+
+/* aynchronous write of a codec verb with data */
+int lola_codec_write(struct lola *chip, unsigned int nid, unsigned int verb,
+		     unsigned int data, unsigned int extdata)
+{
+	verbose_debug("codec_write NID=%x, verb=%x, data=%x, ext=%x\n",
+		      nid, verb, data, extdata);
+	return corb_send_verb(chip, nid, verb, data, extdata);
+}
+
+/* write a codec verb with data and read the returned status */
+int lola_codec_read(struct lola *chip, unsigned int nid, unsigned int verb,
+		    unsigned int data, unsigned int extdata,
+		    unsigned int *val, unsigned int *extval)
+{
+	int err;
+
+	verbose_debug("codec_read NID=%x, verb=%x, data=%x, ext=%x\n",
+		      nid, verb, data, extdata);
+	err = corb_send_verb(chip, nid, verb, data, extdata);
+	if (err < 0)
+		return err;
+	err = rirb_get_response(chip, val, extval);
+	return err;
+}
+
+/* flush all pending codec writes */
+int lola_codec_flush(struct lola *chip)
+{
+	unsigned int tmp;
+	return rirb_get_response(chip, &tmp, NULL);
+}
+
+/*
+ * interrupt handler
+ */
+static irqreturn_t lola_interrupt(int irq, void *dev_id)
+{
+	struct lola *chip = dev_id;
+	unsigned int notify_ins, notify_outs, error_ins, error_outs;
+	int handled = 0;
+	int i;
+
+	notify_ins = notify_outs = error_ins = error_outs = 0;
+	spin_lock(&chip->reg_lock);
+	for (;;) {
+		unsigned int status, in_sts, out_sts;
+		unsigned int reg;
+
+		status = lola_readl(chip, BAR1, DINTSTS);
+		if (!status || status == -1)
+			break;
+
+		in_sts = lola_readl(chip, BAR1, DIINTSTS);
+		out_sts = lola_readl(chip, BAR1, DOINTSTS);
+
+		/* clear Input Interrupts */
+		for (i = 0; in_sts && i < chip->pcm[CAPT].num_streams; i++) {
+			if (!(in_sts & (1 << i)))
+				continue;
+			in_sts &= ~(1 << i);
+			reg = lola_dsd_read(chip, i, STS);
+			if (reg & LOLA_DSD_STS_DESE) /* error */
+				error_ins |= (1 << i);
+			if (reg & LOLA_DSD_STS_BCIS) /* notify */
+				notify_ins |= (1 << i);
+			/* clear */
+			lola_dsd_write(chip, i, STS, reg);
+		}
+
+		/* clear Output Interrupts */
+		for (i = 0; out_sts && i < chip->pcm[PLAY].num_streams; i++) {
+			if (!(out_sts & (1 << i)))
+				continue;
+			out_sts &= ~(1 << i);
+			reg = lola_dsd_read(chip, i + MAX_STREAM_IN_COUNT, STS);
+			if (reg & LOLA_DSD_STS_DESE) /* error */
+				error_outs |= (1 << i);
+			if (reg & LOLA_DSD_STS_BCIS) /* notify */
+				notify_outs |= (1 << i);
+			lola_dsd_write(chip, i + MAX_STREAM_IN_COUNT, STS, reg);
+		}
+
+		if (status & LOLA_DINT_CTRL) {
+			unsigned char rbsts; /* ring status is byte access */
+			rbsts = lola_readb(chip, BAR0, RIRBSTS);
+			rbsts &= LOLA_RIRB_INT_MASK;
+			if (rbsts)
+				lola_writeb(chip, BAR0, RIRBSTS, rbsts);
+			rbsts = lola_readb(chip, BAR0, CORBSTS);
+			rbsts &= LOLA_CORB_INT_MASK;
+			if (rbsts)
+				lola_writeb(chip, BAR0, CORBSTS, rbsts);
+
+			lola_update_rirb(chip);
+		}
+
+		if (status & (LOLA_DINT_FIFOERR | LOLA_DINT_MUERR)) {
+			/* clear global fifo error interrupt */
+			lola_writel(chip, BAR1, DINTSTS,
+				    (status & (LOLA_DINT_FIFOERR | LOLA_DINT_MUERR)));
+		}
+		handled = 1;
+	}
+	spin_unlock(&chip->reg_lock);
+
+	lola_pcm_update(chip, &chip->pcm[CAPT], notify_ins);
+	lola_pcm_update(chip, &chip->pcm[PLAY], notify_outs);
+
+	return IRQ_RETVAL(handled);
+}
+
+
+/*
+ * controller
+ */
+static int reset_controller(struct lola *chip)
+{
+	unsigned int gctl = lola_readl(chip, BAR0, GCTL);
+	unsigned long end_time;
+
+	if (gctl) {
+		/* to be sure */
+		lola_writel(chip, BAR1, BOARD_MODE, 0);
+		return 0;
+	}
+
+	chip->cold_reset = 1;
+	lola_writel(chip, BAR0, GCTL, LOLA_GCTL_RESET);
+	end_time = jiffies + msecs_to_jiffies(200);
+	do {
+		msleep(1);
+		gctl = lola_readl(chip, BAR0, GCTL);
+		if (gctl)
+			break;
+	} while (time_before(jiffies, end_time));
+	if (!gctl) {
+		printk(KERN_ERR SFX "cannot reset controller\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+static void lola_irq_enable(struct lola *chip)
+{
+	unsigned int val;
+
+	/* enalbe all I/O streams */
+	val = (1 << chip->pcm[PLAY].num_streams) - 1;
+	lola_writel(chip, BAR1, DOINTCTL, val);
+	val = (1 << chip->pcm[CAPT].num_streams) - 1;
+	lola_writel(chip, BAR1, DIINTCTL, val);
+
+	/* enable global irqs */
+	val = LOLA_DINT_GLOBAL | LOLA_DINT_CTRL | LOLA_DINT_FIFOERR |
+		LOLA_DINT_MUERR;
+	lola_writel(chip, BAR1, DINTCTL, val);
+}
+
+static void lola_irq_disable(struct lola *chip)
+{
+	lola_writel(chip, BAR1, DINTCTL, 0);
+	lola_writel(chip, BAR1, DIINTCTL, 0);
+	lola_writel(chip, BAR1, DOINTCTL, 0);
+}
+
+static int setup_corb_rirb(struct lola *chip)
+{
+	int err;
+	unsigned char tmp;
+	unsigned long end_time;
+
+	err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
+				  snd_dma_pci_data(chip->pci),
+				  PAGE_SIZE, &chip->rb);
+	if (err < 0)
+		return err;
+
+	chip->corb.addr = chip->rb.addr;
+	chip->corb.buf = (u32 *)chip->rb.area;
+	chip->rirb.addr = chip->rb.addr + 2048;
+	chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
+
+	/* disable ringbuffer DMAs */
+	lola_writeb(chip, BAR0, RIRBCTL, 0);
+	lola_writeb(chip, BAR0, CORBCTL, 0);
+
+	end_time = jiffies + msecs_to_jiffies(200);
+	do {
+		if (!lola_readb(chip, BAR0, RIRBCTL) &&
+		    !lola_readb(chip, BAR0, CORBCTL))
+			break;
+		msleep(1);
+	} while (time_before(jiffies, end_time));
+
+	/* CORB set up */
+	lola_writel(chip, BAR0, CORBLBASE, (u32)chip->corb.addr);
+	lola_writel(chip, BAR0, CORBUBASE, upper_32_bits(chip->corb.addr));
+	/* set the corb size to 256 entries */
+	lola_writeb(chip, BAR0, CORBSIZE, 0x02);
+	/* set the corb write pointer to 0 */
+	lola_writew(chip, BAR0, CORBWP, 0);
+	/* reset the corb hw read pointer */
+	lola_writew(chip, BAR0, CORBRP, LOLA_RBRWP_CLR);
+	/* enable corb dma */
+	lola_writeb(chip, BAR0, CORBCTL, LOLA_RBCTL_DMA_EN);
+	/* clear flags if set */
+	tmp = lola_readb(chip, BAR0, CORBSTS) & LOLA_CORB_INT_MASK;
+	if (tmp)
+		lola_writeb(chip, BAR0, CORBSTS, tmp);
+	chip->corb.wp = 0;
+
+	/* RIRB set up */
+	lola_writel(chip, BAR0, RIRBLBASE, (u32)chip->rirb.addr);
+	lola_writel(chip, BAR0, RIRBUBASE, upper_32_bits(chip->rirb.addr));
+	/* set the rirb size to 256 entries */
+	lola_writeb(chip, BAR0, RIRBSIZE, 0x02);
+	/* reset the rirb hw write pointer */
+	lola_writew(chip, BAR0, RIRBWP, LOLA_RBRWP_CLR);
+	/* set N=1, get RIRB response interrupt for new entry */
+	lola_writew(chip, BAR0, RINTCNT, 1);
+	/* enable rirb dma and response irq */
+	lola_writeb(chip, BAR0, RIRBCTL, LOLA_RBCTL_DMA_EN | LOLA_RBCTL_IRQ_EN);
+	/* clear flags if set */
+	tmp =  lola_readb(chip, BAR0, RIRBSTS) & LOLA_RIRB_INT_MASK;
+	if (tmp)
+		lola_writeb(chip, BAR0, RIRBSTS, tmp);
+	chip->rirb.rp = chip->rirb.cmds = 0;
+
+	return 0;
+}
+
+static void stop_corb_rirb(struct lola *chip)
+{
+	/* disable ringbuffer DMAs */
+	lola_writeb(chip, BAR0, RIRBCTL, 0);
+	lola_writeb(chip, BAR0, CORBCTL, 0);
+}
+
+static void lola_reset_setups(struct lola *chip)
+{
+	/* update the granularity */
+	lola_set_granularity(chip, chip->granularity, true);
+	/* update the sample clock */
+	lola_set_clock_index(chip, chip->clock.cur_index);
+	/* enable unsolicited events of the clock widget */
+	lola_enable_clock_events(chip);
+	/* update the analog gains */
+	lola_setup_all_analog_gains(chip, CAPT, false); /* input, update */
+	/* update SRC configuration if applicable */
+	lola_set_src_config(chip, chip->input_src_mask, false);
+	/* update the analog outputs */
+	lola_setup_all_analog_gains(chip, PLAY, false); /* output, update */
+}
+
+static int lola_parse_tree(struct lola *chip)
+{
+	unsigned int val;
+	int nid, err;
+
+	err = lola_read_param(chip, 0, LOLA_PAR_VENDOR_ID, &val);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Can't read VENDOR_ID\n");
+		return err;
+	}
+	val >>= 16;
+	if (val != 0x1369) {
+		printk(KERN_ERR SFX "Unknown codec vendor 0x%x\n", val);
+		return -EINVAL;
+	}
+
+	err = lola_read_param(chip, 1, LOLA_PAR_FUNCTION_TYPE, &val);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Can't read FUNCTION_TYPE for 0x%x\n", nid);
+		return err;
+	}
+	if (val != 1) {
+		printk(KERN_ERR SFX "Unknown function type %d\n", val);
+		return -EINVAL;
+	}
+
+	err = lola_read_param(chip, 1, LOLA_PAR_SPECIFIC_CAPS, &val);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Can't read SPECCAPS\n");
+		return err;
+	}
+	chip->lola_caps = val;
+	chip->pin[CAPT].num_pins = LOLA_AFG_INPUT_PIN_COUNT(chip->lola_caps);
+	chip->pin[PLAY].num_pins = LOLA_AFG_OUTPUT_PIN_COUNT(chip->lola_caps);
+	snd_printdd(SFX "speccaps=0x%x, pins in=%d, out=%d\n",
+		    chip->lola_caps,
+		    chip->pin[CAPT].num_pins, chip->pin[PLAY].num_pins);
+
+	if (chip->pin[CAPT].num_pins > MAX_AUDIO_INOUT_COUNT ||
+	    chip->pin[PLAY].num_pins > MAX_AUDIO_INOUT_COUNT) {
+		printk(KERN_ERR SFX "Invalid Lola-spec caps 0x%x\n", val);
+		return -EINVAL;
+	}
+
+	nid = 0x02;
+	err = lola_init_pcm(chip, CAPT, &nid);
+	if (err < 0)
+		return err;
+	err = lola_init_pcm(chip, PLAY, &nid);
+	if (err < 0)
+		return err;
+
+	err = lola_init_pins(chip, CAPT, &nid);
+	if (err < 0)
+		return err;
+	err = lola_init_pins(chip, PLAY, &nid);
+	if (err < 0)
+		return err;
+
+	if (LOLA_AFG_CLOCK_WIDGET_PRESENT(chip->lola_caps)) {
+		err = lola_init_clock_widget(chip, nid);
+		if (err < 0)
+			return err;
+		nid++;
+	}
+	if (LOLA_AFG_MIXER_WIDGET_PRESENT(chip->lola_caps)) {
+		err = lola_init_mixer_widget(chip, nid);
+		if (err < 0)
+			return err;
+		nid++;
+	}
+
+	/* enable unsolicited events of the clock widget */
+	err = lola_enable_clock_events(chip);
+	if (err < 0)
+		return err;
+
+	/* if last ResetController was not a ColdReset, we don't know
+	 * the state of the card; initialize here again
+	 */
+	if (!chip->cold_reset) {
+		lola_reset_setups(chip);
+		chip->cold_reset = 1;
+	} else {
+		/* set the granularity if it is not the default */
+		if (chip->granularity != LOLA_GRANULARITY_MIN)
+			lola_set_granularity(chip, chip->granularity, true);
+	}
+
+	return 0;
+}
+
+static void lola_stop_hw(struct lola *chip)
+{
+	stop_corb_rirb(chip);
+	lola_irq_disable(chip);
+}
+
+static void lola_free(struct lola *chip)
+{
+	if (chip->initialized)
+		lola_stop_hw(chip);
+	lola_free_pcm(chip);
+	lola_free_mixer(chip);
+	if (chip->irq >= 0)
+		free_irq(chip->irq, (void *)chip);
+	if (chip->bar[0].remap_addr)
+		iounmap(chip->bar[0].remap_addr);
+	if (chip->bar[1].remap_addr)
+		iounmap(chip->bar[1].remap_addr);
+	if (chip->rb.area)
+		snd_dma_free_pages(&chip->rb);
+	pci_release_regions(chip->pci);
+	pci_disable_device(chip->pci);
+	kfree(chip);
+}
+
+static int lola_dev_free(struct snd_device *device)
+{
+	lola_free(device->device_data);
+	return 0;
+}
+
+static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci,
+				 int dev, struct lola **rchip)
+{
+	struct lola *chip;
+	int err;
+	unsigned int dever;
+	static struct snd_device_ops ops = {
+		.dev_free = lola_dev_free,
+	};
+
+	*rchip = NULL;
+
+	err = pci_enable_device(pci);
+	if (err < 0)
+		return err;
+
+	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	if (!chip) {
+		snd_printk(KERN_ERR SFX "cannot allocate chip\n");
+		pci_disable_device(pci);
+		return -ENOMEM;
+	}
+
+	spin_lock_init(&chip->reg_lock);
+	mutex_init(&chip->open_mutex);
+	chip->card = card;
+	chip->pci = pci;
+	chip->irq = -1;
+
+	chip->granularity = granularity[dev];
+	switch (chip->granularity) {
+	case 8:
+		chip->sample_rate_max = 48000;
+		break;
+	case 16:
+		chip->sample_rate_max = 96000;
+		break;
+	case 32:
+		chip->sample_rate_max = 192000;
+		break;
+	default:
+		snd_printk(KERN_WARNING SFX
+			   "Invalid granularity %d, reset to %d\n",
+			   chip->granularity, LOLA_GRANULARITY_MAX);
+		chip->granularity = LOLA_GRANULARITY_MAX;
+		chip->sample_rate_max = 192000;
+		break;
+	}
+	chip->sample_rate_min = sample_rate_min[dev];
+	if (chip->sample_rate_min > chip->sample_rate_max) {
+		snd_printk(KERN_WARNING SFX
+			   "Invalid sample_rate_min %d, reset to 16000\n",
+			   chip->sample_rate_min);
+		chip->sample_rate_min = 16000;
+	}
+
+	err = pci_request_regions(pci, DRVNAME);
+	if (err < 0) {
+		kfree(chip);
+		pci_disable_device(pci);
+		return err;
+	}
+
+	chip->bar[0].addr = pci_resource_start(pci, 0);
+	chip->bar[0].remap_addr = pci_ioremap_bar(pci, 0);
+	chip->bar[1].addr = pci_resource_start(pci, 2);
+	chip->bar[1].remap_addr = pci_ioremap_bar(pci, 2);
+	if (!chip->bar[0].remap_addr || !chip->bar[1].remap_addr) {
+		snd_printk(KERN_ERR SFX "ioremap error\n");
+		err = -ENXIO;
+		goto errout;
+	}
+
+	pci_set_master(pci);
+
+	err = reset_controller(chip);
+	if (err < 0)
+		goto errout;
+
+	if (request_irq(pci->irq, lola_interrupt, IRQF_SHARED,
+			DRVNAME, chip)) {
+		printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq);
+		err = -EBUSY;
+		goto errout;
+	}
+	chip->irq = pci->irq;
+	synchronize_irq(chip->irq);
+
+	dever = lola_readl(chip, BAR1, DEVER);
+	chip->pcm[CAPT].num_streams = (dever >> 0) & 0x3ff;
+	chip->pcm[PLAY].num_streams = (dever >> 10) & 0x3ff;
+	chip->version = (dever >> 24) & 0xff;
+	snd_printdd(SFX "streams in=%d, out=%d, version=0x%x\n",
+		    chip->pcm[CAPT].num_streams, chip->pcm[PLAY].num_streams,
+		    chip->version);
+
+	/* Test LOLA_BAR1_DEVER */
+	if (chip->pcm[CAPT].num_streams > MAX_STREAM_IN_COUNT ||
+	    chip->pcm[PLAY].num_streams > MAX_STREAM_OUT_COUNT ||
+	    (!chip->pcm[CAPT].num_streams &&
+	     !chip->pcm[PLAY].num_streams)) {
+		printk(KERN_ERR SFX "invalid DEVER = %x\n", dever);
+		err = -EINVAL;
+		goto errout;
+	}
+
+	err = setup_corb_rirb(chip);
+	if (err < 0)
+		goto errout;
+
+	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+	if (err < 0) {
+		snd_printk(KERN_ERR SFX "Error creating device [card]!\n");
+		goto errout;
+	}
+
+	strcpy(card->driver, "Lola");
+	strlcpy(card->shortname, "Digigram Lola", sizeof(card->shortname));
+	snprintf(card->longname, sizeof(card->longname),
+		 "%s at 0x%lx irq %i",
+		 card->shortname, chip->bar[0].addr, chip->irq);
+	strcpy(card->mixername, card->shortname);
+
+	lola_irq_enable(chip);
+
+	chip->initialized = 1;
+	*rchip = chip;
+	return 0;
+
+ errout:
+	lola_free(chip);
+	return err;
+}
+
+static int __devinit lola_probe(struct pci_dev *pci,
+				const struct pci_device_id *pci_id)
+{
+	static int dev;
+	struct snd_card *card;
+	struct lola *chip;
+	int err;
+
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (!enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+
+	err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+	if (err < 0) {
+		snd_printk(KERN_ERR SFX "Error creating card!\n");
+		return err;
+	}
+
+	snd_card_set_dev(card, &pci->dev);
+
+	err = lola_create(card, pci, dev, &chip);
+	if (err < 0)
+		goto out_free;
+	card->private_data = chip;
+
+	err = lola_parse_tree(chip);
+	if (err < 0)
+		goto out_free;
+
+	err = lola_create_pcm(chip);
+	if (err < 0)
+		goto out_free;
+
+	err = lola_create_mixer(chip);
+	if (err < 0)
+		goto out_free;
+
+	lola_proc_debug_new(chip);
+
+	err = snd_card_register(card);
+	if (err < 0)
+		goto out_free;
+
+	pci_set_drvdata(pci, card);
+	dev++;
+	return err;
+out_free:
+	snd_card_free(card);
+	return err;
+}
+
+static void __devexit lola_remove(struct pci_dev *pci)
+{
+	snd_card_free(pci_get_drvdata(pci));
+	pci_set_drvdata(pci, NULL);
+}
+
+/* PCI IDs */
+static DEFINE_PCI_DEVICE_TABLE(lola_ids) = {
+	{ PCI_VDEVICE(DIGIGRAM, 0x0001) },
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, lola_ids);
+
+/* pci_driver definition */
+static struct pci_driver driver = {
+	.name = DRVNAME,
+	.id_table = lola_ids,
+	.probe = lola_probe,
+	.remove = __devexit_p(lola_remove),
+};
+
+static int __init alsa_card_lola_init(void)
+{
+	return pci_register_driver(&driver);
+}
+
+static void __exit alsa_card_lola_exit(void)
+{
+	pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_lola_init)
+module_exit(alsa_card_lola_exit)
diff --git a/sound/pci/lola/lola.h b/sound/pci/lola/lola.h
new file mode 100644
index 000000000000..d5708e29b16d
--- /dev/null
+++ b/sound/pci/lola/lola.h
@@ -0,0 +1,527 @@
+/*
+ *  Support for Digigram Lola PCI-e boards
+ *
+ *  Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
+ *
+ *  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, write to the Free Software Foundation, Inc., 59
+ *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _LOLA_H
+#define _LOLA_H
+
+#define DRVNAME	"snd-lola"
+#define SFX	DRVNAME ": "
+
+/*
+ * Lola HD Audio Registers BAR0
+ */
+#define LOLA_BAR0_GCAP		0x00
+#define LOLA_BAR0_VMIN		0x02
+#define LOLA_BAR0_VMAJ		0x03
+#define LOLA_BAR0_OUTPAY	0x04
+#define LOLA_BAR0_INPAY		0x06
+#define LOLA_BAR0_GCTL		0x08
+#define LOLA_BAR0_WAKEEN	0x0c
+#define LOLA_BAR0_STATESTS	0x0e
+#define LOLA_BAR0_GSTS		0x10
+#define LOLA_BAR0_OUTSTRMPAY	0x18
+#define LOLA_BAR0_INSTRMPAY	0x1a
+#define LOLA_BAR0_INTCTL	0x20
+#define LOLA_BAR0_INTSTS	0x24
+#define LOLA_BAR0_WALCLK	0x30
+#define LOLA_BAR0_SSYNC		0x38
+
+#define LOLA_BAR0_CORBLBASE	0x40
+#define LOLA_BAR0_CORBUBASE	0x44
+#define LOLA_BAR0_CORBWP	0x48	/* no ULONG access */
+#define LOLA_BAR0_CORBRP	0x4a	/* no ULONG access */
+#define LOLA_BAR0_CORBCTL	0x4c	/* no ULONG access */
+#define LOLA_BAR0_CORBSTS	0x4d	/* UCHAR access only */
+#define LOLA_BAR0_CORBSIZE	0x4e	/* no ULONG access */
+
+#define LOLA_BAR0_RIRBLBASE	0x50
+#define LOLA_BAR0_RIRBUBASE	0x54
+#define LOLA_BAR0_RIRBWP	0x58
+#define LOLA_BAR0_RINTCNT	0x5a	/* no ULONG access */
+#define LOLA_BAR0_RIRBCTL	0x5c
+#define LOLA_BAR0_RIRBSTS	0x5d	/* UCHAR access only */
+#define LOLA_BAR0_RIRBSIZE	0x5e	/* no ULONG access */
+
+#define LOLA_BAR0_ICW		0x60
+#define LOLA_BAR0_IRR		0x64
+#define LOLA_BAR0_ICS		0x68
+#define LOLA_BAR0_DPLBASE	0x70
+#define LOLA_BAR0_DPUBASE	0x74
+
+/* stream register offsets from stream base 0x80 */
+#define LOLA_BAR0_SD0_OFFSET	0x80
+#define LOLA_REG0_SD_CTL	0x00
+#define LOLA_REG0_SD_STS	0x03
+#define LOLA_REG0_SD_LPIB	0x04
+#define LOLA_REG0_SD_CBL	0x08
+#define LOLA_REG0_SD_LVI	0x0c
+#define LOLA_REG0_SD_FIFOW	0x0e
+#define LOLA_REG0_SD_FIFOSIZE	0x10
+#define LOLA_REG0_SD_FORMAT	0x12
+#define LOLA_REG0_SD_BDLPL	0x18
+#define LOLA_REG0_SD_BDLPU	0x1c
+
+/*
+ * Lola Digigram Registers BAR1
+ */
+#define LOLA_BAR1_FPGAVER	0x00
+#define LOLA_BAR1_DEVER		0x04
+#define LOLA_BAR1_UCBMV		0x08
+#define LOLA_BAR1_JTAG		0x0c
+#define LOLA_BAR1_UARTRX	0x10
+#define LOLA_BAR1_UARTTX	0x14
+#define LOLA_BAR1_UARTCR	0x18
+#define LOLA_BAR1_NVRAMVER	0x1c
+#define LOLA_BAR1_CTRLSPI	0x20
+#define LOLA_BAR1_DSPI		0x24
+#define LOLA_BAR1_AISPI		0x28
+#define LOLA_BAR1_GRAN		0x2c
+
+#define LOLA_BAR1_DINTCTL	0x80
+#define LOLA_BAR1_DIINTCTL	0x84
+#define LOLA_BAR1_DOINTCTL	0x88
+#define LOLA_BAR1_LRC		0x90
+#define LOLA_BAR1_DINTSTS	0x94
+#define LOLA_BAR1_DIINTSTS	0x98
+#define LOLA_BAR1_DOINTSTS	0x9c
+
+#define LOLA_BAR1_DSD0_OFFSET	0xa0
+#define LOLA_BAR1_DSD_SIZE	0x18
+
+#define LOLA_BAR1_DSDnSTS       0x00
+#define LOLA_BAR1_DSDnLPIB      0x04
+#define LOLA_BAR1_DSDnCTL       0x08
+#define LOLA_BAR1_DSDnLVI       0x0c
+#define LOLA_BAR1_DSDnBDPL      0x10
+#define LOLA_BAR1_DSDnBDPU      0x14
+
+#define LOLA_BAR1_SSYNC		0x03e8
+
+#define LOLA_BAR1_BOARD_CTRL	0x0f00
+#define LOLA_BAR1_BOARD_MODE	0x0f02
+
+#define LOLA_BAR1_SOURCE_GAIN_ENABLE		0x1000
+#define LOLA_BAR1_DEST00_MIX_GAIN_ENABLE	0x1004
+#define LOLA_BAR1_DEST31_MIX_GAIN_ENABLE	0x1080
+#define LOLA_BAR1_SOURCE00_01_GAIN		0x1084
+#define LOLA_BAR1_SOURCE30_31_GAIN		0x10c0
+#define LOLA_BAR1_SOURCE_GAIN(src) \
+	(LOLA_BAR1_SOURCE00_01_GAIN + (src) * 2)
+#define LOLA_BAR1_DEST00_MIX00_01_GAIN		0x10c4
+#define LOLA_BAR1_DEST00_MIX30_31_GAIN		0x1100
+#define LOLA_BAR1_DEST01_MIX00_01_GAIN		0x1104
+#define LOLA_BAR1_DEST01_MIX30_31_GAIN		0x1140
+#define LOLA_BAR1_DEST31_MIX00_01_GAIN		0x1884
+#define LOLA_BAR1_DEST31_MIX30_31_GAIN		0x18c0
+#define LOLA_BAR1_MIX_GAIN(dest, mix) \
+	(LOLA_BAR1_DEST00_MIX00_01_GAIN + (dest) * 0x40 + (mix) * 2)
+#define LOLA_BAR1_ANALOG_CLIP_IN		0x18c4
+#define LOLA_BAR1_PEAKMETERS_SOURCE00_01	0x18c8
+#define LOLA_BAR1_PEAKMETERS_SOURCE30_31	0x1904
+#define LOLA_BAR1_PEAKMETERS_SOURCE(src) \
+	(LOLA_BAR1_PEAKMETERS_SOURCE00_01 + (src) * 2)
+#define LOLA_BAR1_PEAKMETERS_DEST00_01		0x1908
+#define LOLA_BAR1_PEAKMETERS_DEST30_31		0x1944
+#define LOLA_BAR1_PEAKMETERS_DEST(dest) \
+	(LOLA_BAR1_PEAKMETERS_DEST00_01 + (dest) * 2)
+#define LOLA_BAR1_PEAKMETERS_AGC00_01		0x1948
+#define LOLA_BAR1_PEAKMETERS_AGC14_15		0x1964
+#define LOLA_BAR1_PEAKMETERS_AGC(x) \
+	(LOLA_BAR1_PEAKMETERS_AGC00_01 + (x) * 2)
+
+/* GCTL reset bit */
+#define LOLA_GCTL_RESET		(1 << 0)
+/* GCTL unsolicited response enable bit */
+#define LOLA_GCTL_UREN		(1 << 8)
+
+/* CORB/RIRB control, read/write pointer */
+#define LOLA_RBCTL_DMA_EN	0x02	/* enable DMA */
+#define LOLA_RBCTL_IRQ_EN	0x01	/* enable IRQ */
+#define LOLA_RBRWP_CLR		0x8000	/* read/write pointer clear */
+
+#define LOLA_RIRB_EX_UNSOL_EV	0x40000000
+#define LOLA_RIRB_EX_ERROR	0x80000000
+
+/* CORB int mask: CMEI[0] */
+#define LOLA_CORB_INT_CMEI	0x01
+#define LOLA_CORB_INT_MASK	LOLA_CORB_INT_CMEI
+
+/* RIRB int mask: overrun[2], response[0] */
+#define LOLA_RIRB_INT_RESPONSE	0x01
+#define LOLA_RIRB_INT_OVERRUN	0x04
+#define LOLA_RIRB_INT_MASK	(LOLA_RIRB_INT_RESPONSE | LOLA_RIRB_INT_OVERRUN)
+
+/* DINTCTL and DINTSTS */
+#define LOLA_DINT_GLOBAL	0x80000000 /* global interrupt enable bit */
+#define LOLA_DINT_CTRL		0x40000000 /* controller interrupt enable bit */
+#define LOLA_DINT_FIFOERR	0x20000000 /* global fifo error enable bit */
+#define LOLA_DINT_MUERR		0x10000000 /* global microcontroller underrun error */
+
+/* DSDnCTL bits */
+#define LOLA_DSD_CTL_SRST	0x01	/* stream reset bit */
+#define LOLA_DSD_CTL_SRUN	0x02	/* stream DMA start bit */
+#define LOLA_DSD_CTL_IOCE	0x04	/* interrupt on completion enable */
+#define LOLA_DSD_CTL_DEIE	0x10	/* descriptor error interrupt enable */
+#define LOLA_DSD_CTL_VLRCV	0x20	/* valid LRCountValue information in bits 8..31 */
+#define LOLA_LRC_MASK		0xffffff00
+
+/* DSDnSTS */
+#define LOLA_DSD_STS_BCIS	0x04	/* buffer completion interrupt status */
+#define LOLA_DSD_STS_DESE	0x10	/* descriptor error interrupt */
+#define LOLA_DSD_STS_FIFORDY	0x20	/* fifo ready */
+
+#define LOLA_CORB_ENTRIES	256
+
+#define MAX_STREAM_IN_COUNT	16
+#define MAX_STREAM_OUT_COUNT	16
+#define MAX_STREAM_COUNT	16
+#define MAX_PINS		MAX_STREAM_COUNT
+#define MAX_STREAM_BUFFER_COUNT	16
+#define MAX_AUDIO_INOUT_COUNT	16
+
+#define LOLA_CLOCK_TYPE_INTERNAL    0
+#define LOLA_CLOCK_TYPE_AES         1
+#define LOLA_CLOCK_TYPE_AES_SYNC    2
+#define LOLA_CLOCK_TYPE_WORDCLOCK   3
+#define LOLA_CLOCK_TYPE_ETHERSOUND  4
+#define LOLA_CLOCK_TYPE_VIDEO       5
+
+#define LOLA_CLOCK_FORMAT_NONE      0
+#define LOLA_CLOCK_FORMAT_NTSC      1
+#define LOLA_CLOCK_FORMAT_PAL       2
+
+#define MAX_SAMPLE_CLOCK_COUNT  48
+
+/* parameters used with mixer widget's mixer capabilities */
+#define LOLA_PEAK_METER_CAN_AGC_MASK		1
+#define LOLA_PEAK_METER_CAN_ANALOG_CLIP_MASK	2
+
+struct lola_bar {
+	unsigned long addr;
+	void __iomem *remap_addr;
+};
+
+/* CORB/RIRB */
+struct lola_rb {
+	u32 *buf;		/* CORB/RIRB buffer, 8 byte per each entry */
+	dma_addr_t addr;	/* physical address of CORB/RIRB buffer */
+	unsigned short rp, wp;	/* read/write pointers */
+	int cmds;		/* number of pending requests */
+};
+
+/* Pin widget setup */
+struct lola_pin {
+	unsigned int nid;
+	bool is_analog;
+	unsigned int amp_mute;
+	unsigned int amp_step_size;
+	unsigned int amp_num_steps;
+	unsigned int amp_offset;
+	unsigned int max_level;
+	unsigned int config_default_reg;
+	unsigned int fixed_gain_list_len;
+	unsigned int cur_gain_step;
+};
+
+struct lola_pin_array {
+	unsigned int num_pins;
+	unsigned int num_analog_pins;
+	struct lola_pin pins[MAX_PINS];
+};
+
+/* Clock widget setup */
+struct lola_sample_clock {
+	unsigned int type;
+	unsigned int format;
+	unsigned int freq;
+};
+
+struct lola_clock_widget {
+	unsigned int nid;
+	unsigned int items;
+	unsigned int cur_index;
+	unsigned int cur_freq;
+	bool cur_valid;
+	struct lola_sample_clock sample_clock[MAX_SAMPLE_CLOCK_COUNT];
+	unsigned int idx_lookup[MAX_SAMPLE_CLOCK_COUNT];
+};
+
+#define LOLA_MIXER_DIM      32
+struct lola_mixer_array {
+	u32 src_gain_enable;
+	u32 dest_mix_gain_enable[LOLA_MIXER_DIM];
+	u16 src_gain[LOLA_MIXER_DIM];
+	u16 dest_mix_gain[LOLA_MIXER_DIM][LOLA_MIXER_DIM];
+};
+
+/* Mixer widget setup */
+struct lola_mixer_widget {
+	unsigned int nid;
+	unsigned int caps;
+	struct lola_mixer_array __user *array;
+	struct lola_mixer_array *array_saved;
+	unsigned int src_stream_outs;
+	unsigned int src_phys_ins;
+	unsigned int dest_stream_ins;
+	unsigned int dest_phys_outs;
+	unsigned int src_stream_out_ofs;
+	unsigned int dest_phys_out_ofs;
+	unsigned int src_mask;
+	unsigned int dest_mask;
+};
+
+/* Audio stream */
+struct lola_stream {
+	unsigned int nid;	/* audio widget NID */
+	unsigned int index;	/* array index */
+	unsigned int dsd;	/* DSD index */
+	bool can_float;
+	struct snd_pcm_substream *substream; /* assigned PCM substream */
+	struct lola_stream *master;	/* master stream (for multi-channel) */
+
+	/* buffer setup */
+	unsigned int bufsize;
+	unsigned int period_bytes;
+	unsigned int frags;
+
+	/* format + channel setup */
+	unsigned int format_verb;
+
+	/* flags */
+	unsigned int opened:1;
+	unsigned int prepared:1;
+	unsigned int paused:1;
+	unsigned int running:1;
+};
+
+#define PLAY	SNDRV_PCM_STREAM_PLAYBACK
+#define CAPT	SNDRV_PCM_STREAM_CAPTURE
+
+struct lola_pcm {
+	unsigned int num_streams;
+	struct snd_dma_buffer bdl; /* BDL buffer */
+	struct lola_stream streams[MAX_STREAM_COUNT];
+};
+
+/* card instance */
+struct lola {
+	struct snd_card *card;
+	struct pci_dev *pci;
+
+	/* pci resources */
+	struct lola_bar bar[2];
+	int irq;
+
+	/* locks */
+	spinlock_t reg_lock;
+	struct mutex open_mutex;
+
+	/* CORB/RIRB */
+	struct lola_rb corb;
+	struct lola_rb rirb;
+	unsigned int res, res_ex;	/* last read values */
+	/* last command (for debugging) */
+	unsigned int last_cmd_nid, last_verb, last_data, last_extdata;
+
+	/* CORB/RIRB buffers */
+	struct snd_dma_buffer rb;
+
+	/* unsolicited events */
+	unsigned int last_unsol_res;
+
+	/* streams */
+	struct lola_pcm pcm[2];
+
+	/* input src */
+	unsigned int input_src_caps_mask;
+	unsigned int input_src_mask;
+
+	/* pins */
+	struct lola_pin_array pin[2];
+
+	/* clock */
+	struct lola_clock_widget clock;
+	int ref_count_rate;
+	unsigned int sample_rate;
+
+	/* mixer */
+	struct lola_mixer_widget mixer;
+
+	/* hw info */
+	unsigned int version;
+	unsigned int lola_caps;
+
+	/* parameters */
+	unsigned int granularity;
+	unsigned int sample_rate_min;
+	unsigned int sample_rate_max;
+
+	/* flags */
+	unsigned int initialized:1;
+	unsigned int cold_reset:1;
+	unsigned int polling_mode:1;
+
+	/* for debugging */
+	unsigned int debug_res;
+	unsigned int debug_res_ex;
+};
+
+#define BAR0	0
+#define BAR1	1
+
+/* Helper macros */
+#define lola_readl(chip, idx, name) \
+	readl((chip)->bar[idx].remap_addr + LOLA_##idx##_##name)
+#define lola_readw(chip, idx, name) \
+	readw((chip)->bar[idx].remap_addr + LOLA_##idx##_##name)
+#define lola_readb(chip, idx, name) \
+	readb((chip)->bar[idx].remap_addr + LOLA_##idx##_##name)
+#define lola_writel(chip, idx, name, val) \
+	writel((val), (chip)->bar[idx].remap_addr + LOLA_##idx##_##name)
+#define lola_writew(chip, idx, name, val) \
+	writew((val), (chip)->bar[idx].remap_addr + LOLA_##idx##_##name)
+#define lola_writeb(chip, idx, name, val) \
+	writeb((val), (chip)->bar[idx].remap_addr + LOLA_##idx##_##name)
+
+#define lola_dsd_read(chip, dsd, name) \
+	readl((chip)->bar[BAR1].remap_addr + LOLA_BAR1_DSD0_OFFSET + \
+	      (LOLA_BAR1_DSD_SIZE * (dsd)) + LOLA_BAR1_DSDn##name)
+#define lola_dsd_write(chip, dsd, name, val) \
+	writel((val), (chip)->bar[BAR1].remap_addr + LOLA_BAR1_DSD0_OFFSET + \
+	       (LOLA_BAR1_DSD_SIZE * (dsd)) + LOLA_BAR1_DSDn##name)
+
+/* GET verbs HDAudio */
+#define LOLA_VERB_GET_STREAM_FORMAT		0xa00
+#define LOLA_VERB_GET_AMP_GAIN_MUTE		0xb00
+#define LOLA_VERB_PARAMETERS			0xf00
+#define LOLA_VERB_GET_POWER_STATE		0xf05
+#define LOLA_VERB_GET_CONV			0xf06
+#define LOLA_VERB_GET_UNSOLICITED_RESPONSE	0xf08
+#define LOLA_VERB_GET_DIGI_CONVERT_1		0xf0d
+#define LOLA_VERB_GET_CONFIG_DEFAULT		0xf1c
+#define LOLA_VERB_GET_SUBSYSTEM_ID		0xf20
+/* GET verbs Digigram */
+#define LOLA_VERB_GET_FIXED_GAIN		0xfc0
+#define LOLA_VERB_GET_GAIN_SELECT		0xfc1
+#define LOLA_VERB_GET_MAX_LEVEL			0xfc2
+#define LOLA_VERB_GET_CLOCK_LIST		0xfc3
+#define LOLA_VERB_GET_CLOCK_SELECT		0xfc4
+#define LOLA_VERB_GET_CLOCK_STATUS		0xfc5
+
+/* SET verbs HDAudio */
+#define LOLA_VERB_SET_STREAM_FORMAT		0x200
+#define LOLA_VERB_SET_AMP_GAIN_MUTE		0x300
+#define LOLA_VERB_SET_POWER_STATE		0x705
+#define LOLA_VERB_SET_CHANNEL_STREAMID		0x706
+#define LOLA_VERB_SET_UNSOLICITED_ENABLE	0x708
+#define LOLA_VERB_SET_DIGI_CONVERT_1		0x70d
+/* SET verbs Digigram */
+#define LOLA_VERB_SET_GAIN_SELECT		0xf81
+#define LOLA_VERB_SET_CLOCK_SELECT		0xf84
+#define LOLA_VERB_SET_GRANULARITY_STEPS		0xf86
+#define LOLA_VERB_SET_SOURCE_GAIN		0xf87
+#define LOLA_VERB_SET_MIX_GAIN			0xf88
+#define LOLA_VERB_SET_DESTINATION_GAIN		0xf89
+#define LOLA_VERB_SET_SRC			0xf8a
+
+/* Parameter IDs used with LOLA_VERB_PARAMETERS */
+#define LOLA_PAR_VENDOR_ID			0x00
+#define LOLA_PAR_FUNCTION_TYPE			0x05
+#define LOLA_PAR_AUDIO_WIDGET_CAP		0x09
+#define LOLA_PAR_PCM				0x0a
+#define LOLA_PAR_STREAM_FORMATS			0x0b
+#define LOLA_PAR_PIN_CAP			0x0c
+#define LOLA_PAR_AMP_IN_CAP			0x0d
+#define LOLA_PAR_CONNLIST_LEN			0x0e
+#define LOLA_PAR_POWER_STATE			0x0f
+#define LOLA_PAR_GPIO_CAP			0x11
+#define LOLA_PAR_AMP_OUT_CAP			0x12
+#define LOLA_PAR_SPECIFIC_CAPS			0x80
+#define LOLA_PAR_FIXED_GAIN_LIST		0x81
+
+/* extract results of LOLA_PAR_SPECIFIC_CAPS */
+#define LOLA_AFG_MIXER_WIDGET_PRESENT(res)	((res & (1 << 21)) != 0)
+#define LOLA_AFG_CLOCK_WIDGET_PRESENT(res)	((res & (1 << 20)) != 0)
+#define LOLA_AFG_INPUT_PIN_COUNT(res)		((res >> 10) & 0x2ff)
+#define LOLA_AFG_OUTPUT_PIN_COUNT(res)		((res) & 0x2ff)
+
+/* extract results of LOLA_PAR_AMP_IN_CAP / LOLA_PAR_AMP_OUT_CAP */
+#define LOLA_AMP_MUTE_CAPABLE(res)		((res & (1 << 31)) != 0)
+#define LOLA_AMP_STEP_SIZE(res)			((res >> 24) & 0x7f)
+#define LOLA_AMP_NUM_STEPS(res)			((res >> 12) & 0x3ff)
+#define LOLA_AMP_OFFSET(res)			((res) & 0x3ff)
+
+#define LOLA_GRANULARITY_MIN		8
+#define LOLA_GRANULARITY_MAX		32
+#define LOLA_GRANULARITY_STEP		8
+
+/* parameters used with unsolicited command/response */
+#define LOLA_UNSOLICITED_TAG_MASK	0x3f
+#define LOLA_UNSOLICITED_TAG		0x1a
+#define LOLA_UNSOLICITED_ENABLE		0x80
+#define LOLA_UNSOL_RESP_TAG_OFFSET	26
+
+/* count values in the Vendor Specific Mixer Widget's Audio Widget Capabilities */
+#define LOLA_MIXER_SRC_INPUT_PLAY_SEPARATION(res)   ((res >> 2) & 0x1f)
+#define LOLA_MIXER_DEST_REC_OUTPUT_SEPATATION(res)  ((res >> 7) & 0x1f)
+
+int lola_codec_write(struct lola *chip, unsigned int nid, unsigned int verb,
+		     unsigned int data, unsigned int extdata);
+int lola_codec_read(struct lola *chip, unsigned int nid, unsigned int verb,
+		    unsigned int data, unsigned int extdata,
+		    unsigned int *val, unsigned int *extval);
+int lola_codec_flush(struct lola *chip);
+#define lola_read_param(chip, nid, param, val) \
+	lola_codec_read(chip, nid, LOLA_VERB_PARAMETERS, param, 0, val, NULL)
+
+/* PCM */
+int lola_create_pcm(struct lola *chip);
+void lola_free_pcm(struct lola *chip);
+int lola_init_pcm(struct lola *chip, int dir, int *nidp);
+void lola_pcm_update(struct lola *chip, struct lola_pcm *pcm, unsigned int bits);
+
+/* clock */
+int lola_init_clock_widget(struct lola *chip, int nid);
+int lola_set_granularity(struct lola *chip, unsigned int val, bool force);
+int lola_enable_clock_events(struct lola *chip);
+int lola_set_clock_index(struct lola *chip, unsigned int idx);
+int lola_set_clock(struct lola *chip, int idx);
+int lola_set_sample_rate(struct lola *chip, int rate);
+bool lola_update_ext_clock_freq(struct lola *chip, unsigned int val);
+unsigned int lola_sample_rate_convert(unsigned int coded);
+
+/* mixer */
+int lola_init_pins(struct lola *chip, int dir, int *nidp);
+int lola_init_mixer_widget(struct lola *chip, int nid);
+void lola_free_mixer(struct lola *chip);
+int lola_create_mixer(struct lola *chip);
+int lola_setup_all_analog_gains(struct lola *chip, int dir, bool mute);
+void lola_save_mixer(struct lola *chip);
+void lola_restore_mixer(struct lola *chip);
+int lola_set_src_config(struct lola *chip, unsigned int src_mask, bool update);
+
+/* proc */
+#ifdef CONFIG_SND_DEBUG
+void lola_proc_debug_new(struct lola *chip);
+#else
+#define lola_proc_debug_new(chip)
+#endif
+
+#endif /* _LOLA_H */
diff --git a/sound/pci/lola/lola_clock.c b/sound/pci/lola/lola_clock.c
new file mode 100644
index 000000000000..72f8ef0ac865
--- /dev/null
+++ b/sound/pci/lola/lola_clock.c
@@ -0,0 +1,323 @@
+/*
+ *  Support for Digigram Lola PCI-e boards
+ *
+ *  Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
+ *
+ *  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, write to the Free Software Foundation, Inc., 59
+ *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include "lola.h"
+
+unsigned int lola_sample_rate_convert(unsigned int coded)
+{
+	unsigned int freq;
+
+	/* base frequency */
+	switch (coded & 0x3) {
+	case 0:     freq = 48000; break;
+	case 1:     freq = 44100; break;
+	case 2:     freq = 32000; break;
+	default:    return 0;   /* error */
+	}
+
+	/* multiplier / devisor */
+	switch (coded & 0x1c) {
+	case (0 << 2):    break;
+	case (4 << 2):    break;
+	case (1 << 2):    freq *= 2; break;
+	case (2 << 2):    freq *= 4; break;
+	case (5 << 2):    freq /= 2; break;
+	case (6 << 2):    freq /= 4; break;
+	default:        return 0;   /* error */
+	}
+
+	/* ajustement */
+	switch (coded & 0x60) {
+	case (0 << 5):    break;
+	case (1 << 5):    freq = (freq * 999) / 1000; break;
+	case (2 << 5):    freq = (freq * 1001) / 1000; break;
+	default:        return 0;   /* error */
+	}
+	return freq;
+}
+
+/*
+ * Granualrity
+ */
+
+#define LOLA_MAXFREQ_AT_GRANULARITY_MIN         48000
+#define LOLA_MAXFREQ_AT_GRANULARITY_BELOW_MAX   96000
+
+static bool check_gran_clock_compatibility(struct lola *chip,
+					   unsigned int val,
+					   unsigned int freq)
+{
+	if (!chip->granularity)
+		return true;
+
+	if (val < LOLA_GRANULARITY_MIN || val > LOLA_GRANULARITY_MAX ||
+	    (val % LOLA_GRANULARITY_STEP) != 0)
+		return false;
+
+	if (val == LOLA_GRANULARITY_MIN) {
+		if (freq > LOLA_MAXFREQ_AT_GRANULARITY_MIN)
+			return false;
+	} else if (val < LOLA_GRANULARITY_MAX) {
+		if (freq > LOLA_MAXFREQ_AT_GRANULARITY_BELOW_MAX)
+			return false;
+	}
+	return true;
+}
+
+int lola_set_granularity(struct lola *chip, unsigned int val, bool force)
+{
+	int err;
+
+	if (!force) {
+		if (val == chip->granularity)
+			return 0;
+#if 0
+		/* change Gran only if there are no streams allocated ! */
+		if (chip->audio_in_alloc_mask || chip->audio_out_alloc_mask)
+			return -EBUSY;
+#endif
+		if (!check_gran_clock_compatibility(chip, val,
+						    chip->clock.cur_freq))
+			return -EINVAL;
+	}
+
+	chip->granularity = val;
+	val /= LOLA_GRANULARITY_STEP;
+
+	/* audio function group */
+	err = lola_codec_write(chip, 1, LOLA_VERB_SET_GRANULARITY_STEPS,
+			       val, 0);
+	if (err < 0)
+		return err;
+	/* this can be a very slow function !!! */
+	usleep_range(400 * val, 20000);
+	return lola_codec_flush(chip);
+}
+
+/*
+ * Clock widget handling
+ */
+
+int __devinit lola_init_clock_widget(struct lola *chip, int nid)
+{
+	unsigned int val;
+	int i, j, nitems, nb_verbs, idx, idx_list;
+	int err;
+
+	err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
+		return err;
+	}
+
+	if ((val & 0xfff00000) != 0x01f00000) { /* test SubType and Type */
+		snd_printdd("No valid clock widget\n");
+		return 0;
+	}
+
+	chip->clock.nid = nid;
+	chip->clock.items = val & 0xff;
+	snd_printdd("clock_list nid=%x, entries=%d\n", nid,
+		    chip->clock.items);
+	if (chip->clock.items > MAX_SAMPLE_CLOCK_COUNT) {
+		printk(KERN_ERR SFX "CLOCK_LIST too big: %d\n",
+		       chip->clock.items);
+		return -EINVAL;
+	}
+
+	nitems = chip->clock.items;
+	nb_verbs = (nitems + 3) / 4;
+	idx = 0;
+	idx_list = 0;
+	for (i = 0; i < nb_verbs; i++) {
+		unsigned int res_ex;
+		unsigned short items[4];
+
+		err = lola_codec_read(chip, nid, LOLA_VERB_GET_CLOCK_LIST,
+				      idx, 0, &val, &res_ex);
+		if (err < 0) {
+			printk(KERN_ERR SFX "Can't read CLOCK_LIST\n");
+			return -EINVAL;
+		}
+
+		items[0] = val & 0xfff;
+		items[1] = (val >> 16) & 0xfff;
+		items[2] = res_ex & 0xfff;
+		items[3] = (res_ex >> 16) & 0xfff;
+
+		for (j = 0; j < 4; j++) {
+			unsigned char type = items[j] >> 8;
+			unsigned int freq = items[j] & 0xff;
+			int format = LOLA_CLOCK_FORMAT_NONE;
+			bool add_clock = true;
+			if (type == LOLA_CLOCK_TYPE_INTERNAL) {
+				freq = lola_sample_rate_convert(freq);
+				if (freq < chip->sample_rate_min)
+					add_clock = false;
+				else if (freq == 48000) {
+					chip->clock.cur_index = idx_list;
+					chip->clock.cur_freq = 48000;
+					chip->clock.cur_valid = true;
+				}
+			} else if (type == LOLA_CLOCK_TYPE_VIDEO) {
+				freq = lola_sample_rate_convert(freq);
+				if (freq < chip->sample_rate_min)
+					add_clock = false;
+				/* video clock has a format (0:NTSC, 1:PAL)*/
+				if (items[j] & 0x80)
+					format = LOLA_CLOCK_FORMAT_NTSC;
+				else
+					format = LOLA_CLOCK_FORMAT_PAL;
+			}
+			if (add_clock) {
+				struct lola_sample_clock *sc;
+				sc = &chip->clock.sample_clock[idx_list];
+				sc->type = type;
+				sc->format = format;
+				sc->freq = freq;
+				/* keep the index used with the board */
+				chip->clock.idx_lookup[idx_list] = idx;
+				idx_list++;
+			} else {
+				chip->clock.items--;
+			}
+			if (++idx >= nitems)
+				break;
+		}
+	}
+	return 0;
+}
+
+/* enable unsolicited events of the clock widget */
+int lola_enable_clock_events(struct lola *chip)
+{
+	unsigned int res;
+	int err;
+
+	err = lola_codec_read(chip, chip->clock.nid,
+			      LOLA_VERB_SET_UNSOLICITED_ENABLE,
+			      LOLA_UNSOLICITED_ENABLE | LOLA_UNSOLICITED_TAG,
+			      0, &res, NULL);
+	if (err < 0)
+		return err;
+	if (res) {
+		printk(KERN_WARNING SFX "error in enable_clock_events %d\n",
+		       res);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int lola_set_clock_index(struct lola *chip, unsigned int idx)
+{
+	unsigned int res;
+	int err;
+
+	err = lola_codec_read(chip, chip->clock.nid,
+			      LOLA_VERB_SET_CLOCK_SELECT,
+			      chip->clock.idx_lookup[idx],
+			      0, &res, NULL);
+	if (err < 0)
+		return err;
+	if (res) {
+		printk(KERN_WARNING SFX "error in set_clock %d\n", res);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+bool lola_update_ext_clock_freq(struct lola *chip, unsigned int val)
+{
+	unsigned int tag;
+
+	/* the current EXTERNAL clock information gets updated by interrupt
+	 * with an unsolicited response
+	 */
+	if (!val)
+		return false;
+	tag = (val >> LOLA_UNSOL_RESP_TAG_OFFSET) & LOLA_UNSOLICITED_TAG_MASK;
+	if (tag != LOLA_UNSOLICITED_TAG)
+		return false;
+
+	/* only for current = external clocks */
+	if (chip->clock.sample_clock[chip->clock.cur_index].type !=
+	    LOLA_CLOCK_TYPE_INTERNAL) {
+		chip->clock.cur_freq = lola_sample_rate_convert(val & 0x7f);
+		chip->clock.cur_valid = (val & 0x100) != 0;
+	}
+	return true;
+}
+
+int lola_set_clock(struct lola *chip, int idx)
+{
+	int freq = 0;
+	bool valid = false;
+
+	if (idx == chip->clock.cur_index) {
+		/* current clock is allowed */
+		freq = chip->clock.cur_freq;
+		valid = chip->clock.cur_valid;
+	} else if (chip->clock.sample_clock[idx].type ==
+		   LOLA_CLOCK_TYPE_INTERNAL) {
+		/* internal clocks allowed */
+		freq = chip->clock.sample_clock[idx].freq;
+		valid = true;
+	}
+
+	if (!freq || !valid)
+		return -EINVAL;
+
+	if (!check_gran_clock_compatibility(chip, chip->granularity, freq))
+		return -EINVAL;
+
+	if (idx != chip->clock.cur_index) {
+		int err = lola_set_clock_index(chip, idx);
+		if (err < 0)
+			return err;
+		/* update new settings */
+		chip->clock.cur_index = idx;
+		chip->clock.cur_freq = freq;
+		chip->clock.cur_valid = true;
+	}
+	return 0;
+}
+
+int lola_set_sample_rate(struct lola *chip, int rate)
+{
+	int i;
+
+	if (chip->clock.cur_freq == rate && chip->clock.cur_valid)
+		return 0;
+	/* search for new dwClockIndex */
+	for (i = 0; i < chip->clock.items; i++) {
+		if (chip->clock.sample_clock[i].type == LOLA_CLOCK_TYPE_INTERNAL &&
+		    chip->clock.sample_clock[i].freq == rate)
+			break;
+	}
+	if (i >= chip->clock.items)
+		return -EINVAL;
+	return lola_set_clock(chip, i);
+}
+
diff --git a/sound/pci/lola/lola_mixer.c b/sound/pci/lola/lola_mixer.c
new file mode 100644
index 000000000000..5d518f1a712c
--- /dev/null
+++ b/sound/pci/lola/lola_mixer.c
@@ -0,0 +1,839 @@
+/*
+ *  Support for Digigram Lola PCI-e boards
+ *
+ *  Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
+ *
+ *  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, write to the Free Software Foundation, Inc., 59
+ *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+#include "lola.h"
+
+static int __devinit lola_init_pin(struct lola *chip, struct lola_pin *pin,
+				   int dir, int nid)
+{
+	unsigned int val;
+	int err;
+
+	pin->nid = nid;
+	err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
+		return err;
+	}
+	val &= 0x00f00fff; /* test TYPE and bits 0..11 */
+	if (val == 0x00400200)    /* Type = 4, Digital = 1 */
+		pin->is_analog = false;
+	else if (val == 0x0040000a && dir == CAPT) /* Dig=0, InAmp/ovrd */
+		pin->is_analog = true;
+	else if (val == 0x0040000c && dir == PLAY) /* Dig=0, OutAmp/ovrd */
+		pin->is_analog = true;
+	else {
+		printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n", val, nid);
+		return -EINVAL;
+	}
+
+	/* analog parameters only following, so continue in case of Digital pin
+	 */
+	if (!pin->is_analog)
+		return 0;
+
+	if (dir == PLAY)
+		err = lola_read_param(chip, nid, LOLA_PAR_AMP_OUT_CAP, &val);
+	else
+		err = lola_read_param(chip, nid, LOLA_PAR_AMP_IN_CAP, &val);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Can't read AMP-caps for 0x%x\n", nid);
+		return err;
+	}
+
+	pin->amp_mute = LOLA_AMP_MUTE_CAPABLE(val);
+	pin->amp_step_size = LOLA_AMP_STEP_SIZE(val);
+	pin->amp_num_steps = LOLA_AMP_NUM_STEPS(val);
+	if (pin->amp_num_steps) {
+		/* zero as mute state */
+		pin->amp_num_steps++;
+		pin->amp_step_size++;
+	}
+	pin->amp_offset = LOLA_AMP_OFFSET(val);
+
+	err = lola_codec_read(chip, nid, LOLA_VERB_GET_MAX_LEVEL, 0, 0, &val,
+			      NULL);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Can't get MAX_LEVEL 0x%x\n", nid);
+		return err;
+	}
+	pin->max_level = val & 0x3ff;   /* 10 bits */
+
+	pin->config_default_reg = 0;
+	pin->fixed_gain_list_len = 0;
+	pin->cur_gain_step = 0;
+
+	return 0;
+}
+
+int __devinit lola_init_pins(struct lola *chip, int dir, int *nidp)
+{
+	int i, err, nid;
+	nid = *nidp;
+	for (i = 0; i < chip->pin[dir].num_pins; i++, nid++) {
+		err = lola_init_pin(chip, &chip->pin[dir].pins[i], dir, nid);
+		if (err < 0)
+			return err;
+		if (chip->pin[dir].pins[i].is_analog)
+			chip->pin[dir].num_analog_pins++;
+	}
+	*nidp = nid;
+	return 0;
+}
+
+void lola_free_mixer(struct lola *chip)
+{
+	if (chip->mixer.array_saved)
+		vfree(chip->mixer.array_saved);
+}
+
+int __devinit lola_init_mixer_widget(struct lola *chip, int nid)
+{
+	unsigned int val;
+	int err;
+
+	err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
+		return err;
+	}
+
+	if ((val & 0xfff00000) != 0x02f00000) { /* test SubType and Type */
+		snd_printdd("No valid mixer widget\n");
+		return 0;
+	}
+
+	chip->mixer.nid = nid;
+	chip->mixer.caps = val;
+	chip->mixer.array = (struct lola_mixer_array __iomem *)
+		(chip->bar[BAR1].remap_addr + LOLA_BAR1_SOURCE_GAIN_ENABLE);
+
+	/* reserve memory to copy mixer data for sleep mode transitions */
+	chip->mixer.array_saved = vmalloc(sizeof(struct lola_mixer_array));
+
+	/* mixer matrix sources are physical input data and play streams */
+	chip->mixer.src_stream_outs = chip->pcm[PLAY].num_streams;
+	chip->mixer.src_phys_ins = chip->pin[CAPT].num_pins;
+
+	/* mixer matrix destinations are record streams and physical output */
+	chip->mixer.dest_stream_ins = chip->pcm[CAPT].num_streams;
+	chip->mixer.dest_phys_outs = chip->pin[PLAY].num_pins;
+
+	/* mixer matrix can have unused areas between PhysIn and
+	 * Play or Record and PhysOut zones
+	 */
+	chip->mixer.src_stream_out_ofs = chip->mixer.src_phys_ins +
+		LOLA_MIXER_SRC_INPUT_PLAY_SEPARATION(val);
+	chip->mixer.dest_phys_out_ofs = chip->mixer.dest_stream_ins +
+		LOLA_MIXER_DEST_REC_OUTPUT_SEPATATION(val);
+
+	/* example : MixerMatrix of LoLa881
+	 * 0-------8------16-------8------16
+	 * |       |       |       |       |
+	 * | INPUT |       | INPUT |       |
+	 * | ->    |unused | ->    |unused |
+	 * | RECORD|       | OUTPUT|       |
+	 * |       |       |       |       |
+	 * 8--------------------------------
+	 * |       |       |       |       |
+	 * |       |       |       |       |
+	 * |unused |unused |unused |unused |
+	 * |       |       |       |       |
+	 * |       |       |       |       |
+	 * 16-------------------------------
+	 * |       |       |       |       |
+	 * | PLAY  |       | PLAY  |       |
+	 * |  ->   |unused | ->    |unused |
+	 * | RECORD|       | OUTPUT|       |
+	 * |       |       |       |       |
+	 * 8--------------------------------
+	 * |       |       |       |       |
+	 * |       |       |       |       |
+	 * |unused |unused |unused |unused |
+	 * |       |       |       |       |
+	 * |       |       |       |       |
+	 * 16-------------------------------
+	 */
+	if (chip->mixer.src_stream_out_ofs > MAX_AUDIO_INOUT_COUNT ||
+	    chip->mixer.dest_phys_out_ofs > MAX_STREAM_IN_COUNT) {
+		printk(KERN_ERR SFX "Invalid mixer widget size\n");
+		return -EINVAL;
+	}
+
+	chip->mixer.src_mask = ((1U << chip->mixer.src_phys_ins) - 1) |
+		(((1U << chip->mixer.src_stream_outs) - 1)
+		 << chip->mixer.src_stream_out_ofs);
+	chip->mixer.dest_mask = ((1U << chip->mixer.dest_stream_ins) - 1) |
+		(((1U << chip->mixer.dest_phys_outs) - 1)
+		 << chip->mixer.dest_phys_out_ofs);
+
+	return 0;
+}
+
+static int lola_mixer_set_src_gain(struct lola *chip, unsigned int id,
+				   unsigned short gain, bool on)
+{
+	unsigned int oldval, val;
+
+	if (!(chip->mixer.src_mask & (1 << id)))
+		return -EINVAL;
+	writew(gain, &chip->mixer.array->src_gain[id]);
+	oldval = val = readl(&chip->mixer.array->src_gain_enable);
+	if (on)
+		val |= (1 << id);
+	else
+		val &= ~(1 << id);
+	writel(val, &chip->mixer.array->src_gain_enable);
+	lola_codec_flush(chip);
+	/* inform micro-controller about the new source gain */
+	return lola_codec_write(chip, chip->mixer.nid,
+				LOLA_VERB_SET_SOURCE_GAIN, id, 0);
+}
+
+#if 0 /* not used */
+static int lola_mixer_set_src_gains(struct lola *chip, unsigned int mask,
+				    unsigned short *gains)
+{
+	int i;
+
+	if ((chip->mixer.src_mask & mask) != mask)
+		return -EINVAL;
+	for (i = 0; i < LOLA_MIXER_DIM; i++) {
+		if (mask & (1 << i)) {
+			writew(*gains, &chip->mixer.array->src_gain[i]);
+			gains++;
+		}
+	}
+	writel(mask, &chip->mixer.array->src_gain_enable);
+	lola_codec_flush(chip);
+	if (chip->mixer.caps & LOLA_PEAK_METER_CAN_AGC_MASK) {
+		/* update for all srcs at once */
+		return lola_codec_write(chip, chip->mixer.nid,
+					LOLA_VERB_SET_SOURCE_GAIN, 0x80, 0);
+	}
+	/* update manually */
+	for (i = 0; i < LOLA_MIXER_DIM; i++) {
+		if (mask & (1 << i)) {
+			lola_codec_write(chip, chip->mixer.nid,
+					 LOLA_VERB_SET_SOURCE_GAIN, i, 0);
+		}
+	}
+	return 0;
+}
+#endif /* not used */
+
+static int lola_mixer_set_mapping_gain(struct lola *chip,
+				       unsigned int src, unsigned int dest,
+				       unsigned short gain, bool on)
+{
+	unsigned int val;
+
+	if (!(chip->mixer.src_mask & (1 << src)) ||
+	    !(chip->mixer.dest_mask & (1 << dest)))
+		return -EINVAL;
+	if (on)
+		writew(gain, &chip->mixer.array->dest_mix_gain[dest][src]);
+	val = readl(&chip->mixer.array->dest_mix_gain_enable[dest]);
+	if (on)
+		val |= (1 << src);
+	else
+		val &= ~(1 << src);
+	writel(val, &chip->mixer.array->dest_mix_gain_enable[dest]);
+	lola_codec_flush(chip);
+	return lola_codec_write(chip, chip->mixer.nid, LOLA_VERB_SET_MIX_GAIN,
+				src, dest);
+}
+
+static int lola_mixer_set_dest_gains(struct lola *chip, unsigned int id,
+				     unsigned int mask, unsigned short *gains)
+{
+	int i;
+
+	if (!(chip->mixer.dest_mask & (1 << id)) ||
+	    (chip->mixer.src_mask & mask) != mask)
+		return -EINVAL;
+	for (i = 0; i < LOLA_MIXER_DIM; i++) {
+		if (mask & (1 << i)) {
+			writew(*gains, &chip->mixer.array->dest_mix_gain[id][i]);
+			gains++;
+		}
+	}
+	writel(mask, &chip->mixer.array->dest_mix_gain_enable[id]);
+	lola_codec_flush(chip);
+	/* update for all dests at once */
+	return lola_codec_write(chip, chip->mixer.nid,
+				LOLA_VERB_SET_DESTINATION_GAIN, id, 0);
+}
+
+/*
+ */
+
+static int set_analog_volume(struct lola *chip, int dir,
+			     unsigned int idx, unsigned int val,
+			     bool external_call);
+
+int lola_setup_all_analog_gains(struct lola *chip, int dir, bool mute)
+{
+	struct lola_pin *pin;
+	int idx, max_idx;
+
+	pin = chip->pin[dir].pins;
+	max_idx = chip->pin[dir].num_pins;
+	for (idx = 0; idx < max_idx; idx++) {
+		if (pin[idx].is_analog) {
+			unsigned int val = mute ? 0 : pin[idx].cur_gain_step;
+			/* set volume and do not save the value */
+			set_analog_volume(chip, dir, idx, val, false);
+		}
+	}
+	return lola_codec_flush(chip);
+}
+
+void lola_save_mixer(struct lola *chip)
+{
+	/* mute analog output */
+	if (chip->mixer.array_saved) {
+		/* store contents of mixer array */
+		memcpy_fromio(chip->mixer.array_saved, chip->mixer.array,
+			      sizeof(*chip->mixer.array));
+	}
+	lola_setup_all_analog_gains(chip, PLAY, true); /* output mute */
+}
+
+void lola_restore_mixer(struct lola *chip)
+{
+	int i;
+
+	/*lola_reset_setups(chip);*/
+	if (chip->mixer.array_saved) {
+		/* restore contents of mixer array */
+		memcpy_toio(chip->mixer.array, chip->mixer.array_saved,
+			    sizeof(*chip->mixer.array));
+		/* inform micro-controller about all restored values
+		 * and ignore return values
+		 */
+		for (i = 0; i < chip->mixer.src_phys_ins; i++)
+			lola_codec_write(chip, chip->mixer.nid,
+					 LOLA_VERB_SET_SOURCE_GAIN,
+					 i, 0);
+		for (i = 0; i < chip->mixer.src_stream_outs; i++)
+			lola_codec_write(chip, chip->mixer.nid,
+					 LOLA_VERB_SET_SOURCE_GAIN,
+					 chip->mixer.src_stream_out_ofs + i, 0);
+		for (i = 0; i < chip->mixer.dest_stream_ins; i++)
+			lola_codec_write(chip, chip->mixer.nid,
+					 LOLA_VERB_SET_DESTINATION_GAIN,
+					 i, 0);
+		for (i = 0; i < chip->mixer.dest_phys_outs; i++)
+			lola_codec_write(chip, chip->mixer.nid,
+					 LOLA_VERB_SET_DESTINATION_GAIN,
+					 chip->mixer.dest_phys_out_ofs + i, 0);
+		lola_codec_flush(chip);
+	}
+}
+
+/*
+ */
+
+static int set_analog_volume(struct lola *chip, int dir,
+			     unsigned int idx, unsigned int val,
+			     bool external_call)
+{
+	struct lola_pin *pin;
+	int err;
+
+	if (idx >= chip->pin[dir].num_pins)
+		return -EINVAL;
+	pin = &chip->pin[dir].pins[idx];
+	if (!pin->is_analog || pin->amp_num_steps <= val)
+		return -EINVAL;
+	if (external_call && pin->cur_gain_step == val)
+		return 0;
+	if (external_call)
+		lola_codec_flush(chip);
+	err = lola_codec_write(chip, pin->nid,
+			       LOLA_VERB_SET_AMP_GAIN_MUTE, val, 0);
+	if (err < 0)
+		return err;
+	if (external_call)
+		pin->cur_gain_step = val;
+	return 0;
+}
+
+int lola_set_src_config(struct lola *chip, unsigned int src_mask, bool update)
+{
+	int ret = 0;
+	int success = 0;
+	int n, err;
+
+	/* SRC can be activated and the dwInputSRCMask is valid? */
+	if ((chip->input_src_caps_mask & src_mask) != src_mask)
+		return -EINVAL;
+	/* handle all even Inputs - SRC is a stereo setting !!! */
+	for (n = 0; n < chip->pin[CAPT].num_pins; n += 2) {
+		unsigned int mask = 3U << n; /* handle the stereo case */
+		unsigned int new_src, src_state;
+		if (!(chip->input_src_caps_mask & mask))
+			continue;
+		/* if one IO needs SRC, both stereo IO will get SRC */
+		new_src = (src_mask & mask) != 0;
+		if (update) {
+			src_state = (chip->input_src_mask & mask) != 0;
+			if (src_state == new_src)
+				continue;   /* nothing to change for this IO */
+		}
+		err = lola_codec_write(chip, chip->pcm[CAPT].streams[n].nid,
+				       LOLA_VERB_SET_SRC, new_src, 0);
+		if (!err)
+			success++;
+		else
+			ret = err;
+	}
+	if (success)
+		ret = lola_codec_flush(chip);
+	if (!ret)
+		chip->input_src_mask = src_mask;
+	return ret;
+}
+
+/*
+ */
+static int init_mixer_values(struct lola *chip)
+{
+	int i;
+
+	/* all src on */
+	lola_set_src_config(chip, (1 << chip->pin[CAPT].num_pins) - 1, false);
+
+	/* clear all matrix */
+	memset_io(chip->mixer.array, 0, sizeof(*chip->mixer.array));
+	/* set src gain to 0dB */
+	for (i = 0; i < chip->mixer.src_phys_ins; i++)
+		lola_mixer_set_src_gain(chip, i, 336, true); /* 0dB */
+	for (i = 0; i < chip->mixer.src_stream_outs; i++)
+		lola_mixer_set_src_gain(chip,
+					i + chip->mixer.src_stream_out_ofs,
+					336, true); /* 0dB */
+	/* set 1:1 dest gain */
+	for (i = 0; i < chip->mixer.dest_stream_ins; i++) {
+		int src = i % chip->mixer.src_phys_ins;
+		lola_mixer_set_mapping_gain(chip, src, i, 336, true);
+	}
+	for (i = 0; i < chip->mixer.src_stream_outs; i++) {
+		int src = chip->mixer.src_stream_out_ofs + i;
+		int dst = chip->mixer.dest_phys_out_ofs +
+			i % chip->mixer.dest_phys_outs;
+		lola_mixer_set_mapping_gain(chip, src, dst, 336, true);
+	}
+	return 0;
+}
+
+/*
+ * analog mixer control element
+ */
+static int lola_analog_vol_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+	int dir = kcontrol->private_value;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = chip->pin[dir].num_pins;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = chip->pin[dir].pins[0].amp_num_steps;
+	return 0;
+}
+
+static int lola_analog_vol_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+	int dir = kcontrol->private_value;
+	int i;
+
+	for (i = 0; i < chip->pin[dir].num_pins; i++)
+		ucontrol->value.integer.value[i] =
+			chip->pin[dir].pins[i].cur_gain_step;
+	return 0;
+}
+
+static int lola_analog_vol_put(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+	int dir = kcontrol->private_value;
+	int i, err;
+
+	for (i = 0; i < chip->pin[dir].num_pins; i++) {
+		err = set_analog_volume(chip, dir, i,
+					ucontrol->value.integer.value[i],
+					true);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+static int lola_analog_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+			       unsigned int size, unsigned int __user *tlv)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+	int dir = kcontrol->private_value;
+	unsigned int val1, val2;
+	struct lola_pin *pin;
+
+	if (size < 4 * sizeof(unsigned int))
+		return -ENOMEM;
+	pin = &chip->pin[dir].pins[0];
+
+	val2 = pin->amp_step_size * 25;
+	val1 = -1 * (int)pin->amp_offset * (int)val2;
+#ifdef TLV_DB_SCALE_MUTE
+	val2 |= TLV_DB_SCALE_MUTE;
+#endif
+	if (put_user(SNDRV_CTL_TLVT_DB_SCALE, tlv))
+		return -EFAULT;
+	if (put_user(2 * sizeof(unsigned int), tlv + 1))
+		return -EFAULT;
+	if (put_user(val1, tlv + 2))
+		return -EFAULT;
+	if (put_user(val2, tlv + 3))
+		return -EFAULT;
+	return 0;
+}
+
+static struct snd_kcontrol_new lola_analog_mixer __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+		   SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+		   SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK),
+	.info = lola_analog_vol_info,
+	.get = lola_analog_vol_get,
+	.put = lola_analog_vol_put,
+	.tlv.c = lola_analog_vol_tlv,
+};
+
+static int __devinit create_analog_mixer(struct lola *chip, int dir, char *name)
+{
+	if (!chip->pin[dir].num_pins)
+		return 0;
+	/* no analog volumes on digital only adapters */
+	if (chip->pin[dir].num_pins != chip->pin[dir].num_analog_pins)
+		return 0;
+	lola_analog_mixer.name = name;
+	lola_analog_mixer.private_value = dir;
+	return snd_ctl_add(chip->card,
+			   snd_ctl_new1(&lola_analog_mixer, chip));
+}
+
+/*
+ * Hardware sample rate converter on digital input
+ */
+static int lola_input_src_info(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_info *uinfo)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = chip->pin[CAPT].num_pins;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int lola_input_src_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+	int i;
+
+	for (i = 0; i < chip->pin[CAPT].num_pins; i++)
+		ucontrol->value.integer.value[i] =
+			!!(chip->input_src_mask & (1 << i));
+	return 0;
+}
+
+static int lola_input_src_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+	int i;
+	unsigned int mask;
+
+	mask = 0;
+	for (i = 0; i < chip->pin[CAPT].num_pins; i++)
+		if (ucontrol->value.integer.value[i])
+			mask |= 1 << i;
+	return lola_set_src_config(chip, mask, true);
+}
+
+static struct snd_kcontrol_new lola_input_src_mixer __devinitdata = {
+	.name = "Digital SRC Capture Switch",
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.info = lola_input_src_info,
+	.get = lola_input_src_get,
+	.put = lola_input_src_put,
+};
+
+/*
+ * Lola16161 or Lola881 can have Hardware sample rate converters
+ * on its digital input pins
+ */
+static int __devinit create_input_src_mixer(struct lola *chip)
+{
+	if (!chip->input_src_caps_mask)
+		return 0;
+
+	return snd_ctl_add(chip->card,
+			   snd_ctl_new1(&lola_input_src_mixer, chip));
+}
+
+/*
+ * src gain mixer
+ */
+static int lola_src_gain_info(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_info *uinfo)
+{
+	unsigned int count = (kcontrol->private_value >> 8) & 0xff;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = count;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 409;
+	return 0;
+}
+
+static int lola_src_gain_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+	unsigned int ofs = kcontrol->private_value & 0xff;
+	unsigned int count = (kcontrol->private_value >> 8) & 0xff;
+	unsigned int mask, i;
+
+	mask = readl(&chip->mixer.array->src_gain_enable);
+	for (i = 0; i < count; i++) {
+		unsigned int idx = ofs + i;
+		unsigned short val;
+		if (!(chip->mixer.src_mask & (1 << idx)))
+			return -EINVAL;
+		if (mask & (1 << idx))
+			val = readw(&chip->mixer.array->src_gain[idx]) + 1;
+		else
+			val = 0;
+		ucontrol->value.integer.value[i] = val;
+	}
+	return 0;
+}
+
+static int lola_src_gain_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+	unsigned int ofs = kcontrol->private_value & 0xff;
+	unsigned int count = (kcontrol->private_value >> 8) & 0xff;
+	int i, err;
+
+	for (i = 0; i < count; i++) {
+		unsigned int idx = ofs + i;
+		unsigned short val = ucontrol->value.integer.value[i];
+		if (val)
+			val--;
+		err = lola_mixer_set_src_gain(chip, idx, val, !!val);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+/* raw value: 0 = -84dB, 336 = 0dB, 408=18dB, incremented 1 for mute */
+static const DECLARE_TLV_DB_SCALE(lola_src_gain_tlv, -8425, 25, 1);
+
+static struct snd_kcontrol_new lola_src_gain_mixer __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+		   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+	.info = lola_src_gain_info,
+	.get = lola_src_gain_get,
+	.put = lola_src_gain_put,
+	.tlv.p = lola_src_gain_tlv,
+};
+
+static int __devinit create_src_gain_mixer(struct lola *chip,
+					   int num, int ofs, char *name)
+{
+	lola_src_gain_mixer.name = name;
+	lola_src_gain_mixer.private_value = ofs + (num << 8);
+	return snd_ctl_add(chip->card,
+			   snd_ctl_new1(&lola_src_gain_mixer, chip));
+}
+
+/*
+ * destination gain (matrix-like) mixer
+ */
+static int lola_dest_gain_info(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_info *uinfo)
+{
+	unsigned int src_num = (kcontrol->private_value >> 8) & 0xff;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = src_num;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 433;
+	return 0;
+}
+
+static int lola_dest_gain_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+	unsigned int src_ofs = kcontrol->private_value & 0xff;
+	unsigned int src_num = (kcontrol->private_value >> 8) & 0xff;
+	unsigned int dst_ofs = (kcontrol->private_value >> 16) & 0xff;
+	unsigned int dst, mask, i;
+
+	dst = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + dst_ofs;
+	mask = readl(&chip->mixer.array->dest_mix_gain_enable[dst]);
+	for (i = 0; i < src_num; i++) {
+		unsigned int src = src_ofs + i;
+		unsigned short val;
+		if (!(chip->mixer.src_mask & (1 << src)))
+			return -EINVAL;
+		if (mask & (1 << dst))
+			val = readw(&chip->mixer.array->dest_mix_gain[dst][src]) + 1;
+		else
+			val = 0;
+		ucontrol->value.integer.value[i] = val;
+	}
+	return 0;
+}
+
+static int lola_dest_gain_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+	unsigned int src_ofs = kcontrol->private_value & 0xff;
+	unsigned int src_num = (kcontrol->private_value >> 8) & 0xff;
+	unsigned int dst_ofs = (kcontrol->private_value >> 16) & 0xff;
+	unsigned int dst, mask;
+	unsigned short gains[MAX_STREAM_COUNT];
+	int i, num;
+
+	mask = 0;
+	num = 0;
+	for (i = 0; i < src_num; i++) {
+		unsigned short val = ucontrol->value.integer.value[i];
+		if (val) {
+			gains[num++] = val - 1;
+			mask |= 1 << i;
+		}
+	}
+	mask <<= src_ofs;
+	dst = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + dst_ofs;
+	return lola_mixer_set_dest_gains(chip, dst, mask, gains);
+}
+
+static const DECLARE_TLV_DB_SCALE(lola_dest_gain_tlv, -8425, 25, 1);
+
+static struct snd_kcontrol_new lola_dest_gain_mixer __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+		   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+	.info = lola_dest_gain_info,
+	.get = lola_dest_gain_get,
+	.put = lola_dest_gain_put,
+	.tlv.p = lola_dest_gain_tlv,
+};
+
+static int __devinit create_dest_gain_mixer(struct lola *chip,
+					    int src_num, int src_ofs,
+					    int num, int ofs, char *name)
+{
+	lola_dest_gain_mixer.count = num;
+	lola_dest_gain_mixer.name = name;
+	lola_dest_gain_mixer.private_value =
+		src_ofs + (src_num << 8) + (ofs << 16) + (num << 24);
+	return snd_ctl_add(chip->card,
+			  snd_ctl_new1(&lola_dest_gain_mixer, chip));
+}
+
+/*
+ */
+int __devinit lola_create_mixer(struct lola *chip)
+{
+	int err;
+
+	err = create_analog_mixer(chip, PLAY, "Analog Playback Volume");
+	if (err < 0)
+		return err;
+	err = create_analog_mixer(chip, CAPT, "Analog Capture Volume");
+	if (err < 0)
+		return err;
+	err = create_input_src_mixer(chip);
+	if (err < 0)
+		return err;
+	err = create_src_gain_mixer(chip, chip->mixer.src_phys_ins, 0,
+				    "Line Source Gain Volume");
+	if (err < 0)
+		return err;
+	err = create_src_gain_mixer(chip, chip->mixer.src_stream_outs,
+				    chip->mixer.src_stream_out_ofs,
+				    "Stream Source Gain Volume");
+	if (err < 0)
+		return err;
+	err = create_dest_gain_mixer(chip,
+				     chip->mixer.src_phys_ins, 0,
+				     chip->mixer.dest_stream_ins, 0,
+				     "Line Capture Volume");
+	if (err < 0)
+		return err;
+	err = create_dest_gain_mixer(chip,
+				     chip->mixer.src_stream_outs,
+				     chip->mixer.src_stream_out_ofs,
+				     chip->mixer.dest_stream_ins, 0,
+				     "Stream-Loopback Capture Volume");
+	if (err < 0)
+		return err;
+	err = create_dest_gain_mixer(chip,
+				     chip->mixer.src_phys_ins, 0,
+				     chip->mixer.dest_phys_outs,
+				     chip->mixer.dest_phys_out_ofs,
+				     "Line-Loopback Playback Volume");
+	if (err < 0)
+		return err;
+	err = create_dest_gain_mixer(chip,
+				     chip->mixer.src_stream_outs,
+				     chip->mixer.src_stream_out_ofs,
+				     chip->mixer.dest_phys_outs,
+				     chip->mixer.dest_phys_out_ofs,
+				     "Stream Playback Volume");
+	if (err < 0)
+		return err;
+
+	return init_mixer_values(chip);
+}
diff --git a/sound/pci/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c
new file mode 100644
index 000000000000..c44db68eecb5
--- /dev/null
+++ b/sound/pci/lola/lola_pcm.c
@@ -0,0 +1,706 @@
+/*
+ *  Support for Digigram Lola PCI-e boards
+ *
+ *  Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
+ *
+ *  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, write to the Free Software Foundation, Inc., 59
+ *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include "lola.h"
+
+#define LOLA_MAX_BDL_ENTRIES	8
+#define LOLA_MAX_BUF_SIZE	(1024*1024*1024)
+#define LOLA_BDL_ENTRY_SIZE	(16 * 16)
+
+static struct lola_pcm *lola_get_pcm(struct snd_pcm_substream *substream)
+{
+	struct lola *chip = snd_pcm_substream_chip(substream);
+	return &chip->pcm[substream->stream];
+}
+
+static struct lola_stream *lola_get_stream(struct snd_pcm_substream *substream)
+{
+	struct lola_pcm *pcm = lola_get_pcm(substream);
+	unsigned int idx = substream->number;
+	return &pcm->streams[idx];
+}
+
+static unsigned int lola_get_lrc(struct lola *chip)
+{
+	return lola_readl(chip, BAR1, LRC);
+}
+
+static unsigned int lola_get_tstamp(struct lola *chip, bool quick_no_sync)
+{
+	unsigned int tstamp = lola_get_lrc(chip) >> 8;
+	if (chip->granularity) {
+		unsigned int wait_banks = quick_no_sync ? 0 : 8;
+		tstamp += (wait_banks + 1) * chip->granularity - 1;
+		tstamp -= tstamp % chip->granularity;
+	}
+	return tstamp << 8;
+}
+
+/* clear any pending interrupt status */
+static void lola_stream_clear_pending_irq(struct lola *chip,
+					  struct lola_stream *str)
+{
+	unsigned int val = lola_dsd_read(chip, str->dsd, STS);
+	val &= LOLA_DSD_STS_DESE | LOLA_DSD_STS_BCIS;
+	if (val)
+		lola_dsd_write(chip, str->dsd, STS, val);
+}
+
+static void lola_stream_start(struct lola *chip, struct lola_stream *str,
+			      unsigned int tstamp)
+{
+	lola_stream_clear_pending_irq(chip, str);
+	lola_dsd_write(chip, str->dsd, CTL,
+		       LOLA_DSD_CTL_SRUN |
+		       LOLA_DSD_CTL_IOCE |
+		       LOLA_DSD_CTL_DEIE |
+		       LOLA_DSD_CTL_VLRCV |
+		       tstamp);
+}
+
+static void lola_stream_stop(struct lola *chip, struct lola_stream *str,
+			     unsigned int tstamp)
+{
+	lola_dsd_write(chip, str->dsd, CTL,
+		       LOLA_DSD_CTL_IOCE |
+		       LOLA_DSD_CTL_DEIE |
+		       LOLA_DSD_CTL_VLRCV |
+		       tstamp);
+	lola_stream_clear_pending_irq(chip, str);
+}
+
+static void wait_for_srst_clear(struct lola *chip, struct lola_stream *str)
+{
+	unsigned long end_time = jiffies + msecs_to_jiffies(200);
+	while (time_before(jiffies, end_time)) {
+		unsigned int val;
+		val = lola_dsd_read(chip, str->dsd, CTL);
+		if (!(val & LOLA_DSD_CTL_SRST))
+			return;
+		msleep(1);
+	}
+	printk(KERN_WARNING SFX "SRST not clear (stream %d)\n", str->dsd);
+}
+
+static int lola_stream_wait_for_fifo(struct lola *chip,
+				     struct lola_stream *str,
+				     bool ready)
+{
+	unsigned int val = ready ? LOLA_DSD_STS_FIFORDY : 0;
+	unsigned long end_time = jiffies + msecs_to_jiffies(200);
+	while (time_before(jiffies, end_time)) {
+		unsigned int reg = lola_dsd_read(chip, str->dsd, STS);
+		if ((reg & LOLA_DSD_STS_FIFORDY) == val)
+			return 0;
+		msleep(1);
+	}
+	printk(KERN_WARNING SFX "FIFO not ready (stream %d)\n", str->dsd);
+	return -EIO;
+}
+
+/* sync for FIFO ready/empty for all linked streams;
+ * clear paused flag when FIFO gets ready again
+ */
+static int lola_sync_wait_for_fifo(struct lola *chip,
+				   struct snd_pcm_substream *substream,
+				   bool ready)
+{
+	unsigned int val = ready ? LOLA_DSD_STS_FIFORDY : 0;
+	unsigned long end_time = jiffies + msecs_to_jiffies(200);
+	struct snd_pcm_substream *s;
+	int pending = 0;
+
+	while (time_before(jiffies, end_time)) {
+		pending = 0;
+		snd_pcm_group_for_each_entry(s, substream) {
+			struct lola_stream *str;
+			if (s->pcm->card != substream->pcm->card)
+				continue;
+			str = lola_get_stream(s);
+			if (str->prepared && str->paused) {
+				unsigned int reg;
+				reg = lola_dsd_read(chip, str->dsd, STS);
+				if ((reg & LOLA_DSD_STS_FIFORDY) != val) {
+					pending = str->dsd + 1;
+					break;
+				}
+				if (ready)
+					str->paused = 0;
+			}
+		}
+		if (!pending)
+			return 0;
+		msleep(1);
+	}
+	printk(KERN_WARNING SFX "FIFO not ready (pending %d)\n", pending - 1);
+	return -EIO;
+}
+
+/* finish pause - prepare for a new resume */
+static void lola_sync_pause(struct lola *chip,
+			    struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_substream *s;
+
+	lola_sync_wait_for_fifo(chip, substream, false);
+	snd_pcm_group_for_each_entry(s, substream) {
+		struct lola_stream *str;
+		if (s->pcm->card != substream->pcm->card)
+			continue;
+		str = lola_get_stream(s);
+		if (str->paused && str->prepared)
+			lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRUN |
+				       LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE);
+	}
+	lola_sync_wait_for_fifo(chip, substream, true);
+}
+
+static void lola_stream_reset(struct lola *chip, struct lola_stream *str)
+{
+	if (str->prepared) {
+		if (str->paused)
+			lola_sync_pause(chip, str->substream);
+		str->prepared = 0;
+		lola_dsd_write(chip, str->dsd, CTL,
+			       LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE);
+		lola_stream_wait_for_fifo(chip, str, false);
+		lola_stream_clear_pending_irq(chip, str);
+		lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRST);
+		lola_dsd_write(chip, str->dsd, LVI, 0);
+		lola_dsd_write(chip, str->dsd, BDPU, 0);
+		lola_dsd_write(chip, str->dsd, BDPL, 0);
+		wait_for_srst_clear(chip, str);
+	}
+}
+
+static struct snd_pcm_hardware lola_pcm_hw = {
+	.info =			(SNDRV_PCM_INFO_MMAP |
+				 SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				 SNDRV_PCM_INFO_MMAP_VALID |
+				 SNDRV_PCM_INFO_PAUSE),
+	.formats =		(SNDRV_PCM_FMTBIT_S16_LE |
+				 SNDRV_PCM_FMTBIT_S24_LE |
+				 SNDRV_PCM_FMTBIT_S32_LE |
+				 SNDRV_PCM_FMTBIT_FLOAT_LE),
+	.rates =		SNDRV_PCM_RATE_8000_192000,
+	.rate_min =		8000,
+	.rate_max =		192000,
+	.channels_min =		1,
+	.channels_max =		2,
+	.buffer_bytes_max =	LOLA_MAX_BUF_SIZE,
+	.period_bytes_min =	128,
+	.period_bytes_max =	LOLA_MAX_BUF_SIZE / 2,
+	.periods_min =		2,
+	.periods_max =		LOLA_MAX_BDL_ENTRIES,
+	.fifo_size =		0,
+};
+
+static int lola_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct lola *chip = snd_pcm_substream_chip(substream);
+	struct lola_pcm *pcm = lola_get_pcm(substream);
+	struct lola_stream *str = lola_get_stream(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	mutex_lock(&chip->open_mutex);
+	if (str->opened) {
+		mutex_unlock(&chip->open_mutex);
+		return -EBUSY;
+	}
+	str->substream = substream;
+	str->master = NULL;
+	str->opened = 1;
+	runtime->hw = lola_pcm_hw;
+	runtime->hw.channels_max = pcm->num_streams - str->index;
+	if (chip->sample_rate) {
+		/* sample rate is locked */
+		runtime->hw.rate_min = chip->sample_rate;
+		runtime->hw.rate_max = chip->sample_rate;
+	} else {
+		runtime->hw.rate_min = chip->sample_rate_min;
+		runtime->hw.rate_max = chip->sample_rate_max;
+	}
+	chip->ref_count_rate++;
+	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+	/* period size = multiple of chip->granularity (8, 16 or 32 frames)*/
+	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+				   chip->granularity);
+	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+				   chip->granularity);
+	mutex_unlock(&chip->open_mutex);
+	return 0;
+}
+
+static void lola_cleanup_slave_streams(struct lola_pcm *pcm,
+				       struct lola_stream *str)
+{
+	int i;
+	for (i = str->index + 1; i < pcm->num_streams; i++) {
+		struct lola_stream *s = &pcm->streams[i];
+		if (s->master != str)
+			break;
+		s->master = NULL;
+		s->opened = 0;
+	}
+}
+
+static int lola_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct lola *chip = snd_pcm_substream_chip(substream);
+	struct lola_stream *str = lola_get_stream(substream);
+
+	mutex_lock(&chip->open_mutex);
+	if (str->substream == substream) {
+		str->substream = NULL;
+		str->opened = 0;
+	}
+	if (--chip->ref_count_rate == 0) {
+		/* release sample rate */
+		chip->sample_rate = 0;
+	}
+	mutex_unlock(&chip->open_mutex);
+	return 0;
+}
+
+static int lola_pcm_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *hw_params)
+{
+	struct lola_stream *str = lola_get_stream(substream);
+
+	str->bufsize = 0;
+	str->period_bytes = 0;
+	str->format_verb = 0;
+	return snd_pcm_lib_malloc_pages(substream,
+					params_buffer_bytes(hw_params));
+}
+
+static int lola_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	struct lola *chip = snd_pcm_substream_chip(substream);
+	struct lola_pcm *pcm = lola_get_pcm(substream);
+	struct lola_stream *str = lola_get_stream(substream);
+
+	mutex_lock(&chip->open_mutex);
+	lola_stream_reset(chip, str);
+	lola_cleanup_slave_streams(pcm, str);
+	mutex_unlock(&chip->open_mutex);
+	return snd_pcm_lib_free_pages(substream);
+}
+
+/*
+ * set up a BDL entry
+ */
+static int setup_bdle(struct snd_pcm_substream *substream,
+		      struct lola_stream *str, u32 **bdlp,
+		      int ofs, int size)
+{
+	u32 *bdl = *bdlp;
+
+	while (size > 0) {
+		dma_addr_t addr;
+		int chunk;
+
+		if (str->frags >= LOLA_MAX_BDL_ENTRIES)
+			return -EINVAL;
+
+		addr = snd_pcm_sgbuf_get_addr(substream, ofs);
+		/* program the address field of the BDL entry */
+		bdl[0] = cpu_to_le32((u32)addr);
+		bdl[1] = cpu_to_le32(upper_32_bits(addr));
+		/* program the size field of the BDL entry */
+		chunk = snd_pcm_sgbuf_get_chunk_size(substream, ofs, size);
+		bdl[2] = cpu_to_le32(chunk);
+		/* program the IOC to enable interrupt
+		 * only when the whole fragment is processed
+		 */
+		size -= chunk;
+		bdl[3] = size ? 0 : cpu_to_le32(0x01);
+		bdl += 4;
+		str->frags++;
+		ofs += chunk;
+	}
+	*bdlp = bdl;
+	return ofs;
+}
+
+/*
+ * set up BDL entries
+ */
+static int lola_setup_periods(struct lola *chip, struct lola_pcm *pcm,
+			      struct snd_pcm_substream *substream,
+			      struct lola_stream *str)
+{
+	u32 *bdl;
+	int i, ofs, periods, period_bytes;
+
+	period_bytes = str->period_bytes;
+	periods = str->bufsize / period_bytes;
+
+	/* program the initial BDL entries */
+	bdl = (u32 *)(pcm->bdl.area + LOLA_BDL_ENTRY_SIZE * str->index);
+	ofs = 0;
+	str->frags = 0;
+	for (i = 0; i < periods; i++) {
+		ofs = setup_bdle(substream, str, &bdl, ofs, period_bytes);
+		if (ofs < 0)
+			goto error;
+	}
+	return 0;
+
+ error:
+	snd_printk(KERN_ERR SFX "Too many BDL entries: buffer=%d, period=%d\n",
+		   str->bufsize, period_bytes);
+	return -EINVAL;
+}
+
+static unsigned int lola_get_format_verb(struct snd_pcm_substream *substream)
+{
+	unsigned int verb;
+
+	switch (substream->runtime->format) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		verb = 0x00000000;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		verb = 0x00000200;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		verb = 0x00000300;
+		break;
+	case SNDRV_PCM_FORMAT_FLOAT_LE:
+		verb = 0x00001300;
+		break;
+	default:
+		return 0;
+	}
+	verb |= substream->runtime->channels;
+	return verb;
+}
+
+static int lola_set_stream_config(struct lola *chip,
+				  struct lola_stream *str,
+				  int channels)
+{
+	int i, err;
+	unsigned int verb, val;
+
+	/* set format info for all channels
+	 * (with only one command for the first channel)
+	 */
+	err = lola_codec_read(chip, str->nid, LOLA_VERB_SET_STREAM_FORMAT,
+			      str->format_verb, 0, &val, NULL);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Cannot set stream format 0x%x\n",
+		       str->format_verb);
+		return err;
+	}
+
+	/* update stream - channel config */
+	for (i = 0; i < channels; i++) {
+		verb = (str->index << 6) | i;
+		err = lola_codec_read(chip, str[i].nid,
+				      LOLA_VERB_SET_CHANNEL_STREAMID, 0, verb,
+				      &val, NULL);
+		if (err < 0) {
+			printk(KERN_ERR SFX "Cannot set stream channel %d\n", i);
+			return err;
+		}
+	}
+	return 0;
+}
+
+/*
+ * set up the SD for streaming
+ */
+static int lola_setup_controller(struct lola *chip, struct lola_pcm *pcm,
+				 struct lola_stream *str)
+{
+	dma_addr_t bdl;
+
+	if (str->prepared)
+		return -EINVAL;
+
+	/* set up BDL */
+	bdl = pcm->bdl.addr + LOLA_BDL_ENTRY_SIZE * str->index;
+	lola_dsd_write(chip, str->dsd, BDPL, (u32)bdl);
+	lola_dsd_write(chip, str->dsd, BDPU, upper_32_bits(bdl));
+	/* program the stream LVI (last valid index) of the BDL */
+	lola_dsd_write(chip, str->dsd, LVI, str->frags - 1);
+	lola_stream_clear_pending_irq(chip, str);
+
+ 	lola_dsd_write(chip, str->dsd, CTL,
+		       LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE | LOLA_DSD_CTL_SRUN);
+
+	str->prepared = 1;
+
+	return lola_stream_wait_for_fifo(chip, str, true);
+}
+
+static int lola_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct lola *chip = snd_pcm_substream_chip(substream);
+	struct lola_pcm *pcm = lola_get_pcm(substream);
+	struct lola_stream *str = lola_get_stream(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned int bufsize, period_bytes, format_verb;
+	int i, err;
+
+	mutex_lock(&chip->open_mutex);
+	lola_stream_reset(chip, str);
+	lola_cleanup_slave_streams(pcm, str);
+	if (str->index + runtime->channels > pcm->num_streams) {
+		mutex_unlock(&chip->open_mutex);
+		return -EINVAL;
+	}
+	for (i = 1; i < runtime->channels; i++) {
+		str[i].master = str;
+		str[i].opened = 1;
+	}
+	mutex_unlock(&chip->open_mutex);
+
+	bufsize = snd_pcm_lib_buffer_bytes(substream);
+	period_bytes = snd_pcm_lib_period_bytes(substream);
+	format_verb = lola_get_format_verb(substream);
+
+	str->bufsize = bufsize;
+	str->period_bytes = period_bytes;
+	str->format_verb = format_verb;
+
+	err = lola_setup_periods(chip, pcm, substream, str);
+	if (err < 0)
+		return err;
+
+	err = lola_set_sample_rate(chip, runtime->rate);
+	if (err < 0)
+		return err;
+	chip->sample_rate = runtime->rate;	/* sample rate gets locked */
+
+	err = lola_set_stream_config(chip, str, runtime->channels);
+	if (err < 0)
+		return err;
+
+	err = lola_setup_controller(chip, pcm, str);
+	if (err < 0) {
+		lola_stream_reset(chip, str);
+		return err;
+	}
+
+	return 0;
+}
+
+static int lola_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct lola *chip = snd_pcm_substream_chip(substream);
+	struct lola_stream *str;
+	struct snd_pcm_substream *s;
+	unsigned int start;
+	unsigned int tstamp;
+	bool sync_streams;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		start = 1;
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_STOP:
+		start = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * sample correct synchronization is only needed starting several
+	 * streams. On stop or if only one stream do as quick as possible
+	 */
+	sync_streams = (start && snd_pcm_stream_linked(substream));
+	tstamp = lola_get_tstamp(chip, !sync_streams);
+	spin_lock(&chip->reg_lock);
+	snd_pcm_group_for_each_entry(s, substream) {
+		if (s->pcm->card != substream->pcm->card)
+			continue;
+		str = lola_get_stream(s);
+		if (start)
+			lola_stream_start(chip, str, tstamp);
+		else
+			lola_stream_stop(chip, str, tstamp);
+		str->running = start;
+		str->paused = !start;
+		snd_pcm_trigger_done(s, substream);
+	}
+	spin_unlock(&chip->reg_lock);
+	return 0;
+}
+
+static snd_pcm_uframes_t lola_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct lola *chip = snd_pcm_substream_chip(substream);
+	struct lola_stream *str = lola_get_stream(substream);
+	unsigned int pos = lola_dsd_read(chip, str->dsd, LPIB);
+
+	if (pos >= str->bufsize)
+		pos = 0;
+	return bytes_to_frames(substream->runtime, pos);
+}
+
+void lola_pcm_update(struct lola *chip, struct lola_pcm *pcm, unsigned int bits)
+{
+	int i;
+
+	for (i = 0; bits && i < pcm->num_streams; i++) {
+		if (bits & (1 << i)) {
+			struct lola_stream *str = &pcm->streams[i];
+			if (str->substream && str->running)
+				snd_pcm_period_elapsed(str->substream);
+			bits &= ~(1 << i);
+		}
+	}
+}
+
+static struct snd_pcm_ops lola_pcm_ops = {
+	.open = lola_pcm_open,
+	.close = lola_pcm_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = lola_pcm_hw_params,
+	.hw_free = lola_pcm_hw_free,
+	.prepare = lola_pcm_prepare,
+	.trigger = lola_pcm_trigger,
+	.pointer = lola_pcm_pointer,
+	.page = snd_pcm_sgbuf_ops_page,
+};
+
+int __devinit lola_create_pcm(struct lola *chip)
+{
+	struct snd_pcm *pcm;
+	int i, err;
+
+	for (i = 0; i < 2; i++) {
+		err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
+					  snd_dma_pci_data(chip->pci),
+					  PAGE_SIZE, &chip->pcm[i].bdl);
+		if (err < 0)
+			return err;
+	}
+
+	err = snd_pcm_new(chip->card, "Digigram Lola", 0,
+			  chip->pcm[SNDRV_PCM_STREAM_PLAYBACK].num_streams,
+			  chip->pcm[SNDRV_PCM_STREAM_CAPTURE].num_streams,
+			  &pcm);
+	if (err < 0)
+		return err;
+	strlcpy(pcm->name, "Digigram Lola", sizeof(pcm->name));
+	pcm->private_data = chip;
+	for (i = 0; i < 2; i++) {
+		if (chip->pcm[i].num_streams)
+			snd_pcm_set_ops(pcm, i, &lola_pcm_ops);
+	}
+	/* buffer pre-allocation */
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+					      snd_dma_pci_data(chip->pci),
+					      1024 * 64, 32 * 1024 * 1024);
+	return 0;
+}
+
+void lola_free_pcm(struct lola *chip)
+{
+	snd_dma_free_pages(&chip->pcm[0].bdl);
+	snd_dma_free_pages(&chip->pcm[1].bdl);
+}
+
+/*
+ */
+
+static int lola_init_stream(struct lola *chip, struct lola_stream *str,
+			    int idx, int nid, int dir)
+{
+	unsigned int val;
+	int err;
+
+	str->nid = nid;
+	str->index = idx;
+	str->dsd = idx;
+	if (dir == PLAY)
+		str->dsd += MAX_STREAM_IN_COUNT;
+	err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
+		return err;
+	}
+	if (dir == PLAY) {
+		/* test TYPE and bits 0..11 (no test bit9 : Digital = 0/1) */
+		if ((val & 0x00f00dff) != 0x00000010) {
+			printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n",
+			       val, nid);
+			return -EINVAL;
+		}
+	} else {
+		/* test TYPE and bits 0..11 (no test bit9 : Digital = 0/1)
+		 * (bug : ignore bit8: Conn list = 0/1)
+		 */
+		if ((val & 0x00f00cff) != 0x00100010) {
+			printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n",
+			       val, nid);
+			return -EINVAL;
+		}
+		/* test bit9:DIGITAL and bit12:SRC_PRESENT*/
+		if ((val & 0x00001200) == 0x00001200)
+			chip->input_src_caps_mask |= (1 << idx);
+	}
+
+	err = lola_read_param(chip, nid, LOLA_PAR_STREAM_FORMATS, &val);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Can't read FORMATS 0x%x\n", nid);
+		return err;
+	}
+	val &= 3;
+	if (val == 3)
+		str->can_float = true;
+	if (!(val & 1)) {
+		printk(KERN_ERR SFX "Invalid formats 0x%x for 0x%x", val, nid);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int __devinit lola_init_pcm(struct lola *chip, int dir, int *nidp)
+{
+	struct lola_pcm *pcm = &chip->pcm[dir];
+	int i, nid, err;
+
+	nid = *nidp;
+	for (i = 0; i < pcm->num_streams; i++, nid++) {
+		err = lola_init_stream(chip, &pcm->streams[i], i, nid, dir);
+		if (err < 0)
+			return err;
+	}
+	*nidp = nid;
+	return 0;
+}
diff --git a/sound/pci/lola/lola_proc.c b/sound/pci/lola/lola_proc.c
new file mode 100644
index 000000000000..9d7daf897c9d
--- /dev/null
+++ b/sound/pci/lola/lola_proc.c
@@ -0,0 +1,222 @@
+/*
+ *  Support for Digigram Lola PCI-e boards
+ *
+ *  Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
+ *
+ *  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, write to the Free Software Foundation, Inc., 59
+ *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/pcm.h>
+#include "lola.h"
+
+static void print_audio_widget(struct snd_info_buffer *buffer,
+			       struct lola *chip, int nid, const char *name)
+{
+	unsigned int val;
+
+	lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+	snd_iprintf(buffer, "Node 0x%02x %s wcaps 0x%x\n", nid, name, val);
+	lola_read_param(chip, nid, LOLA_PAR_STREAM_FORMATS, &val);
+	snd_iprintf(buffer, "  Formats: 0x%x\n", val);
+}
+
+static void print_pin_widget(struct snd_info_buffer *buffer,
+			     struct lola *chip, int nid, unsigned int ampcap,
+			     const char *name)
+{
+	unsigned int val;
+
+	lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+	snd_iprintf(buffer, "Node 0x%02x %s wcaps 0x%x\n", nid, name, val);
+	if (val == 0x00400200)
+		return;
+	lola_read_param(chip, nid, ampcap, &val);
+	snd_iprintf(buffer, "  Amp-Caps: 0x%x\n", val);
+	snd_iprintf(buffer, "    mute=%d, step-size=%d, steps=%d, ofs=%d\n",
+		    LOLA_AMP_MUTE_CAPABLE(val),
+		    LOLA_AMP_STEP_SIZE(val),
+		    LOLA_AMP_NUM_STEPS(val),
+		    LOLA_AMP_OFFSET(val));
+	lola_codec_read(chip, nid, LOLA_VERB_GET_MAX_LEVEL, 0, 0, &val, NULL);
+	snd_iprintf(buffer, "  Max-level: 0x%x\n", val);
+}
+
+static void print_clock_widget(struct snd_info_buffer *buffer,
+			       struct lola *chip, int nid)
+{
+	int i, j, num_clocks;
+	unsigned int val;
+
+	lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+	snd_iprintf(buffer, "Node 0x%02x [Clock] wcaps 0x%x\n", nid, val);
+	num_clocks = val & 0xff;
+	for (i = 0; i < num_clocks; i += 4) {
+		unsigned int res_ex;
+		unsigned short items[4];
+		const char *name;
+
+		lola_codec_read(chip, nid, LOLA_VERB_GET_CLOCK_LIST,
+				i, 0, &val, &res_ex);
+		items[0] = val & 0xfff;
+		items[1] = (val >> 16) & 0xfff;
+		items[2] = res_ex & 0xfff;
+		items[3] = (res_ex >> 16) & 0xfff;
+		for (j = 0; j < 4; j++) {
+			unsigned char type = items[j] >> 8;
+			unsigned int freq = items[j] & 0xff;
+			if (i + j >= num_clocks)
+				break;
+			if (type == LOLA_CLOCK_TYPE_INTERNAL) {
+				name = "Internal";
+				freq = lola_sample_rate_convert(freq);
+			} else if (type == LOLA_CLOCK_TYPE_VIDEO) {
+				name = "Video";
+				freq = lola_sample_rate_convert(freq);
+			} else {
+				name = "Other";
+			}
+			snd_iprintf(buffer, "  Clock %d: Type %d:%s, freq=%d\n",
+				    i + j, type, name, freq);
+		}
+	}
+}
+
+static void print_mixer_widget(struct snd_info_buffer *buffer,
+			       struct lola *chip, int nid)
+{
+	unsigned int val;
+
+	lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+	snd_iprintf(buffer, "Node 0x%02x [Mixer] wcaps 0x%x\n", nid, val);
+}
+
+static void lola_proc_codec_read(struct snd_info_entry *entry,
+				 struct snd_info_buffer *buffer)
+{
+	struct lola *chip = entry->private_data;
+	unsigned int val;
+	int i, nid;
+
+	lola_read_param(chip, 0, LOLA_PAR_VENDOR_ID, &val);
+	snd_iprintf(buffer, "Vendor: 0x%08x\n", val);
+	lola_read_param(chip, 1, LOLA_PAR_FUNCTION_TYPE, &val);
+	snd_iprintf(buffer, "Function Type: %d\n", val);
+	lola_read_param(chip, 1, LOLA_PAR_SPECIFIC_CAPS, &val);
+	snd_iprintf(buffer, "Specific-Caps: 0x%08x\n", val);
+	snd_iprintf(buffer, "  Pins-In %d, Pins-Out %d\n",
+		    chip->pin[CAPT].num_pins, chip->pin[PLAY].num_pins);
+	nid = 2;
+	for (i = 0; i < chip->pcm[CAPT].num_streams; i++, nid++)
+		print_audio_widget(buffer, chip, nid, "[Audio-In]");
+	for (i = 0; i < chip->pcm[PLAY].num_streams; i++, nid++)
+		print_audio_widget(buffer, chip, nid, "[Audio-Out]");
+	for (i = 0; i < chip->pin[CAPT].num_pins; i++, nid++)
+		print_pin_widget(buffer, chip, nid, LOLA_PAR_AMP_IN_CAP,
+				 "[Pin-In]");
+	for (i = 0; i < chip->pin[PLAY].num_pins; i++, nid++)
+		print_pin_widget(buffer, chip, nid, LOLA_PAR_AMP_OUT_CAP,
+				 "[Pin-Out]");
+	if (LOLA_AFG_CLOCK_WIDGET_PRESENT(chip->lola_caps)) {
+		print_clock_widget(buffer, chip, nid);
+		nid++;
+	}
+	if (LOLA_AFG_MIXER_WIDGET_PRESENT(chip->lola_caps)) {
+		print_mixer_widget(buffer, chip, nid);
+		nid++;
+	}
+}
+
+/* direct codec access for debugging */
+static void lola_proc_codec_rw_write(struct snd_info_entry *entry,
+				     struct snd_info_buffer *buffer)
+{
+	struct lola *chip = entry->private_data;
+	char line[64];
+	unsigned int id, verb, data, extdata;
+	while (!snd_info_get_line(buffer, line, sizeof(line))) {
+		if (sscanf(line, "%i %i %i %i", &id, &verb, &data, &extdata) != 4)
+			continue;
+		lola_codec_read(chip, id, verb, data, extdata,
+				&chip->debug_res,
+				&chip->debug_res_ex);
+	}
+}
+
+static void lola_proc_codec_rw_read(struct snd_info_entry *entry,
+				    struct snd_info_buffer *buffer)
+{
+	struct lola *chip = entry->private_data;
+	snd_iprintf(buffer, "0x%x 0x%x\n", chip->debug_res, chip->debug_res_ex);
+}
+
+/*
+ * dump some registers
+ */
+static void lola_proc_regs_read(struct snd_info_entry *entry,
+				struct snd_info_buffer *buffer)
+{
+	struct lola *chip = entry->private_data;
+	int i;
+
+	for (i = 0; i < 0x40; i += 4) {
+		snd_iprintf(buffer, "BAR0 %02x: %08x\n", i,
+			    readl(chip->bar[BAR0].remap_addr + i));
+	}
+	snd_iprintf(buffer, "\n");
+	for (i = 0; i < 0x30; i += 4) {
+		snd_iprintf(buffer, "BAR1 %02x: %08x\n", i,
+			    readl(chip->bar[BAR1].remap_addr + i));
+	}
+	snd_iprintf(buffer, "\n");
+	for (i = 0x80; i < 0xa0; i += 4) {
+		snd_iprintf(buffer, "BAR1 %02x: %08x\n", i,
+			    readl(chip->bar[BAR1].remap_addr + i));
+	}
+	snd_iprintf(buffer, "\n");
+	for (i = 0; i < 32; i++) {
+		snd_iprintf(buffer, "DSD %02x STS  %08x\n", i,
+			    lola_dsd_read(chip, i, STS));
+		snd_iprintf(buffer, "DSD %02x LPIB %08x\n", i,
+			    lola_dsd_read(chip, i, LPIB));
+		snd_iprintf(buffer, "DSD %02x CTL  %08x\n", i,
+			    lola_dsd_read(chip, i, CTL));
+		snd_iprintf(buffer, "DSD %02x LVIL %08x\n", i,
+			    lola_dsd_read(chip, i, LVI));
+		snd_iprintf(buffer, "DSD %02x BDPL %08x\n", i,
+			    lola_dsd_read(chip, i, BDPL));
+		snd_iprintf(buffer, "DSD %02x BDPU %08x\n", i,
+			    lola_dsd_read(chip, i, BDPU));
+	}
+}
+
+void __devinit lola_proc_debug_new(struct lola *chip)
+{
+	struct snd_info_entry *entry;
+
+	if (!snd_card_proc_new(chip->card, "codec", &entry))
+		snd_info_set_text_ops(entry, chip, lola_proc_codec_read);
+	if (!snd_card_proc_new(chip->card, "codec_rw", &entry)) {
+		snd_info_set_text_ops(entry, chip, lola_proc_codec_rw_read);
+		entry->mode |= S_IWUSR;
+		entry->c.text.write = lola_proc_codec_rw_write;
+	}
+	if (!snd_card_proc_new(chip->card, "regs", &entry))
+		snd_info_set_text_ops(entry, chip, lola_proc_regs_read);
+}
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index 961d98297695..9cea84c3e0c6 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -1000,7 +1000,7 @@ static void device_change_handler(struct work_struct *work)
 				   chip->lineout_sw_ctl);
 		if (mix->anded_reset)
 			msleep(10);
-		check_mute(chip, &mix->amp_mute, 1, mix->auto_mute_notify,
+		check_mute(chip, &mix->amp_mute, !IS_G4DA, mix->auto_mute_notify,
 			   chip->speaker_sw_ctl);
 	} else {
 		/* unmute speaker, mute others */
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c
index af3c73053ee4..28afbbf69ce0 100644
--- a/sound/soc/atmel/sam9g20_wm8731.c
+++ b/sound/soc/atmel/sam9g20_wm8731.c
@@ -184,7 +184,7 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = {
 	.codec_dai_name = "wm8731-hifi",
 	.init = at91sam9g20ek_wm8731_init,
 	.platform_name = "atmel-pcm-audio",
-	.codec_name = "wm8731-codec.0-001b",
+	.codec_name = "wm8731.0-001b",
 	.ops = &at91sam9g20ek_ops,
 };
 
diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c
index cb99f04abe88..1d3e258c9ea8 100644
--- a/sound/soc/au1x/db1200.c
+++ b/sound/soc/au1x/db1200.c
@@ -77,7 +77,7 @@ static struct snd_soc_dai_link db1200_i2s_dai = {
 	.codec_dai_name	= "wm8731-hifi",
 	.cpu_dai_name	= "au1xpsc_i2s.1",
 	.platform_name	= "au1xpsc-pcm.1",
-	.codec_name	= "wm8731-codec.0-001b",
+	.codec_name	= "wm8731.0-001b",
 	.ops		= &db1200_i2s_wm8731_ops,
 };
 
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c
index 5a2fd8abaefa..98b44b316e78 100644
--- a/sound/soc/blackfin/bf5xx-ac97-pcm.c
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c
@@ -243,6 +243,9 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
 
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 {
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	int ret;
 
@@ -314,6 +317,9 @@ static struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
 
 static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 {
+	struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
 	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
 	struct snd_dma_buffer *buf = &substream->dma_buffer;
 	size_t size = bf5xx_pcm_hardware.buffer_bytes_max
@@ -377,6 +383,9 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 	struct snd_dma_buffer *buf;
 	int stream;
 #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
+	struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
 	size_t size = bf5xx_pcm_hardware.buffer_bytes_max *
 		sizeof(struct ac97_frame) / 4;
 #endif
@@ -405,8 +414,6 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 	}
 #endif
 	}
-	if (sport_handle)
-		sport_done(sport_handle);
 }
 
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
@@ -458,7 +465,7 @@ static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
 
 static struct platform_driver bf5xx_pcm_driver = {
 	.driver = {
-			.name = "bf5xx-pcm-audio",
+			.name = "bfin-ac97-pcm-audio",
 			.owner = THIS_MODULE,
 	},
 
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c
index ffbac26b9bce..6d2162590889 100644
--- a/sound/soc/blackfin/bf5xx-ac97.c
+++ b/sound/soc/blackfin/bf5xx-ac97.c
@@ -41,48 +41,7 @@
  *		anomaly does not affect blackfin sound drivers.
 */
 
-static int *cmd_count;
-static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
-
-#define SPORT_REQ(x) \
-	[x] = {P_SPORT##x##_TFS, P_SPORT##x##_DTPRI, P_SPORT##x##_TSCLK, \
-	       P_SPORT##x##_RFS, P_SPORT##x##_DRPRI, P_SPORT##x##_RSCLK, 0}
-static u16 sport_req[][7] = {
-#ifdef SPORT0_TCR1
-	SPORT_REQ(0),
-#endif
-#ifdef SPORT1_TCR1
-	SPORT_REQ(1),
-#endif
-#ifdef SPORT2_TCR1
-	SPORT_REQ(2),
-#endif
-#ifdef SPORT3_TCR1
-	SPORT_REQ(3),
-#endif
-};
-
-#define SPORT_PARAMS(x) \
-	[x] = { \
-		.dma_rx_chan = CH_SPORT##x##_RX, \
-		.dma_tx_chan = CH_SPORT##x##_TX, \
-		.err_irq     = IRQ_SPORT##x##_ERROR, \
-		.regs        = (struct sport_register *)SPORT##x##_TCR1, \
-	}
-static struct sport_param sport_params[4] = {
-#ifdef SPORT0_TCR1
-	SPORT_PARAMS(0),
-#endif
-#ifdef SPORT1_TCR1
-	SPORT_PARAMS(1),
-#endif
-#ifdef SPORT2_TCR1
-	SPORT_PARAMS(2),
-#endif
-#ifdef SPORT3_TCR1
-	SPORT_PARAMS(3),
-#endif
-};
+static struct sport_device *ac97_sport_handle;
 
 void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src,
 		size_t count, unsigned int chan_mask)
@@ -140,7 +99,8 @@ static unsigned int sport_tx_curr_frag(struct sport_device *sport)
 
 static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
 {
-	struct sport_device *sport = sport_handle;
+	struct sport_device *sport = ac97_sport_handle;
+	int *cmd_count = sport->private_data;
 	int nextfrag = sport_tx_curr_frag(sport);
 	struct ac97_frame *nextwrite;
 
@@ -161,6 +121,7 @@ static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
 static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97,
 	unsigned short reg)
 {
+	struct sport_device *sport_handle = ac97_sport_handle;
 	struct ac97_frame out_frame[2], in_frame[2];
 
 	pr_debug("%s enter 0x%x\n", __func__, reg);
@@ -185,6 +146,8 @@ static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97,
 void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 	unsigned short val)
 {
+	struct sport_device *sport_handle = ac97_sport_handle;
+
 	pr_debug("%s enter 0x%x:0x%04x\n", __func__, reg, val);
 
 	if (sport_handle->tx_run) {
@@ -203,28 +166,19 @@ void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 
 static void bf5xx_ac97_warm_reset(struct snd_ac97 *ac97)
 {
-#if defined(CONFIG_BF54x) || defined(CONFIG_BF561) || \
- (defined(BF537_FAMILY) && (CONFIG_SND_BF5XX_SPORT_NUM == 1))
-
-#define CONCAT(a, b, c) a ## b ## c
-#define BFIN_SPORT_RFS(x) CONCAT(P_SPORT, x, _RFS)
-
-	u16 per = BFIN_SPORT_RFS(CONFIG_SND_BF5XX_SPORT_NUM);
-	u16 gpio = P_IDENT(BFIN_SPORT_RFS(CONFIG_SND_BF5XX_SPORT_NUM));
+	struct sport_device *sport_handle = ac97_sport_handle;
+	u16 gpio = P_IDENT(sport_handle->pin_req[3]);
 
 	pr_debug("%s enter\n", __func__);
 
-	peripheral_free(per);
+	peripheral_free_list(sport_handle->pin_req);
 	gpio_request(gpio, "bf5xx-ac97");
 	gpio_direction_output(gpio, 1);
 	udelay(2);
 	gpio_set_value(gpio, 0);
 	udelay(1);
 	gpio_free(gpio);
-	peripheral_request(per, "soc-audio");
-#else
-	pr_info("%s: Not implemented\n", __func__);
-#endif
+	peripheral_request_list(sport_handle->pin_req, "soc-audio");
 }
 
 static void bf5xx_ac97_cold_reset(struct snd_ac97 *ac97)
@@ -306,18 +260,32 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
 #define bf5xx_ac97_resume	NULL
 #endif
 
-static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
+static struct snd_soc_dai_driver bfin_ac97_dai = {
+	.ac97_control = 1,
+	.suspend = bf5xx_ac97_suspend,
+	.resume = bf5xx_ac97_resume,
+	.playback = {
+		.stream_name = "AC97 Playback",
+		.channels_min = 2,
+#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
+		.channels_max = 6,
+#else
+		.channels_max = 2,
+#endif
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
+	.capture = {
+		.stream_name = "AC97 Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
+};
+
+static int __devinit asoc_bfin_ac97_probe(struct platform_device *pdev)
 {
-	int ret = 0;
-	cmd_count = (int *)get_zeroed_page(GFP_KERNEL);
-	if (cmd_count == NULL)
-		return -ENOMEM;
-
-	if (peripheral_request_list(sport_req[sport_num], "soc-audio")) {
-		pr_err("Requesting Peripherals failed\n");
-		ret =  -EFAULT;
-		goto peripheral_err;
-	}
+	struct sport_device *sport_handle;
+	int ret;
 
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
 	/* Request PB3 as reset pin */
@@ -329,12 +297,14 @@ static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
 	}
 	gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1);
 #endif
-	sport_handle = sport_init(&sport_params[sport_num], 2, \
-			sizeof(struct ac97_frame), NULL);
+
+	sport_handle = sport_init(pdev, 2, sizeof(struct ac97_frame),
+		PAGE_SIZE);
 	if (!sport_handle) {
 		ret = -ENODEV;
 		goto sport_err;
 	}
+
 	/*SPORT works in TDM mode to simulate AC97 transfers*/
 #if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
 	ret = sport_set_multichannel(sport_handle, 16, 0x3FF, 1);
@@ -361,67 +331,37 @@ static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
 		goto sport_config_err;
 	}
 
+	ret = snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai);
+	if (ret) {
+		pr_err("Failed to register DAI: %d\n", ret);
+		goto sport_config_err;
+	}
+
+	ac97_sport_handle = sport_handle;
+
 	return 0;
 
 sport_config_err:
-	kfree(sport_handle);
+	sport_done(sport_handle);
 sport_err:
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
 	gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
 gpio_err:
 #endif
-	peripheral_free_list(sport_req[sport_num]);
-peripheral_err:
-	free_page((unsigned long)cmd_count);
-	cmd_count = NULL;
 
 	return ret;
 }
 
-static int bf5xx_ac97_remove(struct snd_soc_dai *dai)
+static int __devexit asoc_bfin_ac97_remove(struct platform_device *pdev)
 {
-	free_page((unsigned long)cmd_count);
-	cmd_count = NULL;
-	peripheral_free_list(sport_req[sport_num]);
+	struct sport_device *sport_handle = platform_get_drvdata(pdev);
+
+	snd_soc_unregister_dai(&pdev->dev);
+	sport_done(sport_handle);
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
 	gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
 #endif
-	return 0;
-}
-
-struct snd_soc_dai_driver bfin_ac97_dai = {
-	.ac97_control = 1,
-	.probe = bf5xx_ac97_probe,
-	.remove = bf5xx_ac97_remove,
-	.suspend = bf5xx_ac97_suspend,
-	.resume = bf5xx_ac97_resume,
-	.playback = {
-		.stream_name = "AC97 Playback",
-		.channels_min = 2,
-#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
-		.channels_max = 6,
-#else
-		.channels_max = 2,
-#endif
-		.rates = SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
-	.capture = {
-		.stream_name = "AC97 Capture",
-		.channels_min = 2,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
-};
-EXPORT_SYMBOL_GPL(bfin_ac97_dai);
-
-static __devinit int asoc_bfin_ac97_probe(struct platform_device *pdev)
-{
-	return snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai);
-}
 
-static int __devexit asoc_bfin_ac97_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_dai(&pdev->dev);
 	return 0;
 }
 
diff --git a/sound/soc/blackfin/bf5xx-ad1836.c b/sound/soc/blackfin/bf5xx-ad1836.c
index 83012da9dfc2..ea4951cf5526 100644
--- a/sound/soc/blackfin/bf5xx-ad1836.c
+++ b/sound/soc/blackfin/bf5xx-ad1836.c
@@ -29,22 +29,12 @@
 #include <asm/portmux.h>
 
 #include "../codecs/ad1836.h"
-#include "bf5xx-sport.h"
 
 #include "bf5xx-tdm-pcm.h"
 #include "bf5xx-tdm.h"
 
 static struct snd_soc_card bf5xx_ad1836;
 
-static int bf5xx_ad1836_startup(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-	snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-	return 0;
-}
-
 static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
 {
@@ -75,23 +65,33 @@ static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
 }
 
 static struct snd_soc_ops bf5xx_ad1836_ops = {
-	.startup = bf5xx_ad1836_startup,
 	.hw_params = bf5xx_ad1836_hw_params,
 };
 
-static struct snd_soc_dai_link bf5xx_ad1836_dai = {
-	.name = "ad1836",
-	.stream_name = "AD1836",
-	.cpu_dai_name = "bf5xx-tdm",
-	.codec_dai_name = "ad1836-hifi",
-	.platform_name = "bf5xx-tdm-pcm-audio",
-	.codec_name = "ad1836-codec.0",
-	.ops = &bf5xx_ad1836_ops,
+static struct snd_soc_dai_link bf5xx_ad1836_dai[] = {
+	{
+		.name = "ad1836",
+		.stream_name = "AD1836",
+		.cpu_dai_name = "bfin-tdm.0",
+		.codec_dai_name = "ad1836-hifi",
+		.platform_name = "bfin-tdm-pcm-audio",
+		.codec_name = "ad1836.0",
+		.ops = &bf5xx_ad1836_ops,
+	},
+	{
+		.name = "ad1836",
+		.stream_name = "AD1836",
+		.cpu_dai_name = "bfin-tdm.1",
+		.codec_dai_name = "ad1836-hifi",
+		.platform_name = "bfin-tdm-pcm-audio",
+		.codec_name = "ad1836.0",
+		.ops = &bf5xx_ad1836_ops,
+	},
 };
 
 static struct snd_soc_card bf5xx_ad1836 = {
-	.name = "bf5xx_ad1836",
-	.dai_link = &bf5xx_ad1836_dai,
+	.name = "bfin-ad1836",
+	.dai_link = &bf5xx_ad1836_dai[CONFIG_SND_BF5XX_SPORT_NUM],
 	.num_links = 1,
 };
 
diff --git a/sound/soc/blackfin/bf5xx-ad193x.c b/sound/soc/blackfin/bf5xx-ad193x.c
index d3ccb926b5e4..d6651c033cb7 100644
--- a/sound/soc/blackfin/bf5xx-ad193x.c
+++ b/sound/soc/blackfin/bf5xx-ad193x.c
@@ -38,30 +38,28 @@
 #include <asm/portmux.h>
 
 #include "../codecs/ad193x.h"
-#include "bf5xx-sport.h"
 
 #include "bf5xx-tdm-pcm.h"
 #include "bf5xx-tdm.h"
 
 static struct snd_soc_card bf5xx_ad193x;
 
-static int bf5xx_ad193x_startup(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-	snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-	return 0;
-}
-
 static int bf5xx_ad193x_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->cpu_dai;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	unsigned int clk = 0;
 	unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7};
 	int ret = 0;
+
+	switch (params_rate(params)) {
+	case 48000:
+		clk = 12288000;
+		break;
+	}
+
 	/* set cpu DAI configuration */
 	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
 		SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
@@ -74,6 +72,12 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
 	if (ret < 0)
 		return ret;
 
+	/* set the codec system clock for DAC and ADC */
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
 	/* set codec DAI slots, 8 channels, all channels are enabled */
 	ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 0xFF, 8, 32);
 	if (ret < 0)
@@ -89,23 +93,33 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
 }
 
 static struct snd_soc_ops bf5xx_ad193x_ops = {
-	.startup = bf5xx_ad193x_startup,
 	.hw_params = bf5xx_ad193x_hw_params,
 };
 
-static struct snd_soc_dai_link bf5xx_ad193x_dai = {
-	.name = "ad193x",
-	.stream_name = "AD193X",
-	.cpu_dai_name = "bf5xx-tdm",
-	.codec_dai_name ="ad193x-hifi",
-	.platform_name = "bf5xx-tdm-pcm-audio",
-	.codec_name = "ad193x-codec.5",
-	.ops = &bf5xx_ad193x_ops,
+static struct snd_soc_dai_link bf5xx_ad193x_dai[] = {
+	{
+		.name = "ad193x",
+		.stream_name = "AD193X",
+		.cpu_dai_name = "bfin-tdm.0",
+		.codec_dai_name ="ad193x-hifi",
+		.platform_name = "bfin-tdm-pcm-audio",
+		.codec_name = "ad193x.5",
+		.ops = &bf5xx_ad193x_ops,
+	},
+	{
+		.name = "ad193x",
+		.stream_name = "AD193X",
+		.cpu_dai_name = "bfin-tdm.1",
+		.codec_dai_name ="ad193x-hifi",
+		.platform_name = "bfin-tdm-pcm-audio",
+		.codec_name = "ad193x.5",
+		.ops = &bf5xx_ad193x_ops,
+	},
 };
 
 static struct snd_soc_card bf5xx_ad193x = {
-	.name = "bf5xx_ad193x",
-	.dai_link = &bf5xx_ad193x_dai,
+	.name = "bfin-ad193x",
+	.dai_link = &bf5xx_ad193x_dai[CONFIG_SND_BF5XX_SPORT_NUM],
 	.num_links = 1,
 };
 
diff --git a/sound/soc/blackfin/bf5xx-ad1980.c b/sound/soc/blackfin/bf5xx-ad1980.c
index d57c9c9c9883..06a84b211b52 100644
--- a/sound/soc/blackfin/bf5xx-ad1980.c
+++ b/sound/soc/blackfin/bf5xx-ad1980.c
@@ -47,39 +47,34 @@
 #include <asm/portmux.h>
 
 #include "../codecs/ad1980.h"
-#include "bf5xx-sport.h"
+
 #include "bf5xx-ac97-pcm.h"
 #include "bf5xx-ac97.h"
 
 static struct snd_soc_card bf5xx_board;
 
-static int bf5xx_board_startup(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-	pr_debug("%s enter\n", __func__);
-	snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-	return 0;
-}
-
-static struct snd_soc_ops bf5xx_board_ops = {
-	.startup = bf5xx_board_startup,
-};
-
-static struct snd_soc_dai_link bf5xx_board_dai = {
-	.name = "AC97",
-	.stream_name = "AC97 HiFi",
-	.cpu_dai_name = "bfin-ac97",
-	.codec_dai_name = "ad1980-hifi",
-	.platform_name = "bfin-pcm-audio",
-	.codec_name = "ad1980-codec",
-	.ops = &bf5xx_board_ops,
+static struct snd_soc_dai_link bf5xx_board_dai[] = {
+	{
+		.name = "AC97",
+		.stream_name = "AC97 HiFi",
+		.cpu_dai_name = "bfin-ac97.0",
+		.codec_dai_name = "ad1980-hifi",
+		.platform_name = "bfin-ac97-pcm-audio",
+		.codec_name = "ad1980",
+	},
+	{
+		.name = "AC97",
+		.stream_name = "AC97 HiFi",
+		.cpu_dai_name = "bfin-ac97.1",
+		.codec_dai_name = "ad1980-hifi",
+		.platform_name = "bfin-ac97-pcm-audio",
+		.codec_name = "ad1980",
+	},
 };
 
 static struct snd_soc_card bf5xx_board = {
-	.name = "bf5xx-board",
-	.dai_link = &bf5xx_board_dai,
+	.name = "bfin-ad1980",
+	.dai_link = &bf5xx_board_dai[CONFIG_SND_BF5XX_SPORT_NUM],
 	.num_links = 1,
 };
 
diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c
index 732fb8bad076..732a247f2527 100644
--- a/sound/soc/blackfin/bf5xx-ad73311.c
+++ b/sound/soc/blackfin/bf5xx-ad73311.c
@@ -145,16 +145,6 @@ static int bf5xx_probe(struct platform_device *pdev)
 	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->cpu_dai;
-
-	pr_debug("%s enter\n", __func__);
-	snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-	return 0;
-}
-
 static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
 {
@@ -176,24 +166,34 @@ static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
 
 
 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_name = "bf5xx-i2s",
-	.codec_dai_name = "ad73311-hifi",
-	.platform_name = "bfin-pcm-audio",
-	.codec_name = "ad73311-codec",
-	.ops = &bf5xx_ad73311_ops,
+static struct snd_soc_dai_link bf5xx_ad73311_dai[] = {
+	{
+		.name = "ad73311",
+		.stream_name = "AD73311",
+		.cpu_dai_name = "bfin-i2s.0",
+		.codec_dai_name = "ad73311-hifi",
+		.platform_name = "bfin-i2s-pcm-audio",
+		.codec_name = "ad73311",
+		.ops = &bf5xx_ad73311_ops,
+	},
+	{
+		.name = "ad73311",
+		.stream_name = "AD73311",
+		.cpu_dai_name = "bfin-i2s.1",
+		.codec_dai_name = "ad73311-hifi",
+		.platform_name = "bfin-i2s-pcm-audio",
+		.codec_name = "ad73311",
+		.ops = &bf5xx_ad73311_ops,
+	},
 };
 
 static struct snd_soc_card bf5xx_ad73311 = {
-	.name = "bf5xx_ad73311",
+	.name = "bfin-ad73311",
 	.probe = bf5xx_probe,
-	.dai_link = &bf5xx_ad73311_dai,
+	.dai_link = &bf5xx_ad73311_dai[CONFIG_SND_BF5XX_SPORT_NUM],
 	.num_links = 1,
 };
 
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c
index 890a0dccf902..b5101efd1c87 100644
--- a/sound/soc/blackfin/bf5xx-i2s-pcm.c
+++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c
@@ -148,10 +148,15 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
 
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 {
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
 	int ret;
 
 	pr_debug("%s enter\n", __func__);
+
 	snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
 
 	ret = snd_pcm_hw_constraint_integer(runtime, \
@@ -159,9 +164,14 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 	if (ret < 0)
 		goto out;
 
-	if (sport_handle != NULL)
+	if (sport_handle != NULL) {
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			sport_handle->tx_buf = buf->area;
+		else
+			sport_handle->rx_buf = buf->area;
+
 		runtime->private_data = sport_handle;
-	else {
+	} else {
 		pr_err("sport_handle is NULL\n");
 		return -1;
 	}
@@ -214,11 +224,6 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 	pr_debug("%s, area:%p, size:0x%08lx\n", __func__,
 		buf->area, buf->bytes);
 
-	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-		sport_handle->tx_buf = buf->area;
-	else
-		sport_handle->rx_buf = buf->area;
-
 	return 0;
 }
 
@@ -239,8 +244,6 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 		dma_free_coherent(NULL, buf->bytes, buf->area, 0);
 		buf->area = NULL;
 	}
-	if (sport_handle)
-		sport_done(sport_handle);
 }
 
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
@@ -292,7 +295,7 @@ static int __devexit bfin_i2s_soc_platform_remove(struct platform_device *pdev)
 
 static struct platform_driver bfin_i2s_pcm_driver = {
 	.driver = {
-			.name = "bfin-pcm-audio",
+			.name = "bfin-i2s-pcm-audio",
 			.owner = THIS_MODULE,
 	},
 
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c
index d453b1e9d607..00cc3e00b2fe 100644
--- a/sound/soc/blackfin/bf5xx-i2s.c
+++ b/sound/soc/blackfin/bf5xx-i2s.c
@@ -51,59 +51,24 @@ struct bf5xx_i2s_port {
 	int configured;
 };
 
-static struct bf5xx_i2s_port bf5xx_i2s;
-static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
-
-static struct sport_param sport_params[2] = {
-	{
-		.dma_rx_chan	= CH_SPORT0_RX,
-		.dma_tx_chan	= CH_SPORT0_TX,
-		.err_irq	= IRQ_SPORT0_ERROR,
-		.regs		= (struct sport_register *)SPORT0_TCR1,
-	},
-	{
-		.dma_rx_chan	= CH_SPORT1_RX,
-		.dma_tx_chan	= CH_SPORT1_TX,
-		.err_irq	= IRQ_SPORT1_ERROR,
-		.regs		= (struct sport_register *)SPORT1_TCR1,
-	}
-};
-
-/*
- * Setting the TFS pin selector for SPORT 0 based on whether the selected
- * port id F or G. If the port is F then no conflict should exist for the
- * TFS. When Port G is selected and EMAC then there is a conflict between
- * the PHY interrupt line and TFS.  Current settings prevent the conflict
- * by ignoring the TFS pin when Port G is selected. This allows both
- * codecs and EMAC using Port G concurrently.
- */
-#ifdef CONFIG_BF527_SPORT0_PORTG
-#define LOCAL_SPORT0_TFS (0)
-#else
-#define LOCAL_SPORT0_TFS (P_SPORT0_TFS)
-#endif
-
-static u16 sport_req[][7] = { {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
-		P_SPORT0_DRPRI, P_SPORT0_RSCLK, LOCAL_SPORT0_TFS, 0},
-		{P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, P_SPORT1_DRPRI,
-		P_SPORT1_RSCLK, P_SPORT1_TFS, 0} };
-
 static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 		unsigned int fmt)
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
+	struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
 	int ret = 0;
 
 	/* 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;
+		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;
+		bf5xx_i2s->tcr1 |= TFSR;
+		bf5xx_i2s->rcr1 |= RFSR;
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
 		ret = -EINVAL;
@@ -135,29 +100,35 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+	struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
 	int ret = 0;
 
-	bf5xx_i2s.tcr2 &= ~0x1f;
-	bf5xx_i2s.rcr2 &= ~0x1f;
+	bf5xx_i2s->tcr2 &= ~0x1f;
+	bf5xx_i2s->rcr2 &= ~0x1f;
 	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		bf5xx_i2s->tcr2 |= 7;
+		bf5xx_i2s->rcr2 |= 7;
+		sport_handle->wdsize = 1;
 	case SNDRV_PCM_FORMAT_S16_LE:
-		bf5xx_i2s.tcr2 |= 15;
-		bf5xx_i2s.rcr2 |= 15;
+		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;
+		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;
+		bf5xx_i2s->tcr2 |= 31;
+		bf5xx_i2s->rcr2 |= 31;
 		sport_handle->wdsize = 4;
 		break;
 	}
 
-	if (!bf5xx_i2s.configured) {
+	if (!bf5xx_i2s->configured) {
 		/*
 		 * TX and RX are not independent,they are enabled at the
 		 * same time, even if only one side is running. So, we
@@ -166,16 +137,16 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
 		 *
 		 * CPU DAI:slave mode.
 		 */
-		bf5xx_i2s.configured = 1;
-		ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1,
-				      bf5xx_i2s.rcr2, 0, 0);
+		bf5xx_i2s->configured = 1;
+		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, bf5xx_i2s.tcr1,
-				      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;
@@ -188,41 +159,19 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
 static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
 			       struct snd_soc_dai *dai)
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+	struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
+
 	pr_debug("%s enter\n", __func__);
 	/* No active stream, SPORT is allowed to be configured again. */
 	if (!dai->active)
-		bf5xx_i2s.configured = 0;
-}
-
-static int bf5xx_i2s_probe(struct snd_soc_dai *dai)
-{
-	pr_debug("%s enter\n", __func__);
-	if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
-		pr_err("Requesting Peripherals failed\n");
-		return -EFAULT;
-	}
-
-	/* request DMA for SPORT */
-	sport_handle = sport_init(&sport_params[sport_num], 4, \
-			2 * sizeof(u32), NULL);
-	if (!sport_handle) {
-		peripheral_free_list(&sport_req[sport_num][0]);
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static int bf5xx_i2s_remove(struct snd_soc_dai *dai)
-{
-	pr_debug("%s enter\n", __func__);
-	peripheral_free_list(&sport_req[sport_num][0]);
-	return 0;
+		bf5xx_i2s->configured = 0;
 }
 
 #ifdef CONFIG_PM
 static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
 
 	pr_debug("%s : sport %d\n", __func__, dai->id);
 
@@ -235,19 +184,21 @@ static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
 
 static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+	struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
 	int ret;
 
 	pr_debug("%s : sport %d\n", __func__, dai->id);
 
-	ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1,
-				      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, bf5xx_i2s.tcr1,
-				      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;
@@ -266,8 +217,11 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
 		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
 		SNDRV_PCM_RATE_96000)
 
-#define BF5XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\
-	SNDRV_PCM_FMTBIT_S32_LE)
+#define BF5XX_I2S_FORMATS \
+	(SNDRV_PCM_FMTBIT_S8 | \
+	 SNDRV_PCM_FMTBIT_S16_LE | \
+	 SNDRV_PCM_FMTBIT_S24_LE | \
+	 SNDRV_PCM_FMTBIT_S32_LE)
 
 static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
 	.shutdown	= bf5xx_i2s_shutdown,
@@ -276,8 +230,6 @@ static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
 };
 
 static struct snd_soc_dai_driver bf5xx_i2s_dai = {
-	.probe = bf5xx_i2s_probe,
-	.remove = bf5xx_i2s_remove,
 	.suspend = bf5xx_i2s_suspend,
 	.resume = bf5xx_i2s_resume,
 	.playback = {
@@ -293,23 +245,45 @@ static struct snd_soc_dai_driver bf5xx_i2s_dai = {
 	.ops = &bf5xx_i2s_dai_ops,
 };
 
-static int bfin_i2s_drv_probe(struct platform_device *pdev)
+static int __devinit bf5xx_i2s_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai);
+	struct sport_device *sport_handle;
+	int ret;
+
+	/* configure SPORT for I2S */
+	sport_handle = sport_init(pdev, 4, 2 * sizeof(u32),
+		sizeof(struct bf5xx_i2s_port));
+	if (!sport_handle)
+		return -ENODEV;
+
+	/* register with the ASoC layers */
+	ret = snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai);
+	if (ret) {
+		pr_err("Failed to register DAI: %d\n", ret);
+		sport_done(sport_handle);
+		return ret;
+	}
+
+	return 0;
 }
 
-static int __devexit bfin_i2s_drv_remove(struct platform_device *pdev)
+static int __devexit bf5xx_i2s_remove(struct platform_device *pdev)
 {
+	struct sport_device *sport_handle = platform_get_drvdata(pdev);
+
+	pr_debug("%s enter\n", __func__);
+
 	snd_soc_unregister_dai(&pdev->dev);
+	sport_done(sport_handle);
+
 	return 0;
 }
 
 static struct platform_driver bfin_i2s_driver = {
-	.probe = bfin_i2s_drv_probe,
-	.remove = __devexit_p(bfin_i2s_drv_remove),
-
+	.probe  = bf5xx_i2s_probe,
+	.remove = __devexit_p(bf5xx_i2s_remove),
 	.driver = {
-		.name = "bf5xx-i2s",
+		.name = "bfin-i2s",
 		.owner = THIS_MODULE,
 	},
 };
diff --git a/sound/soc/blackfin/bf5xx-sport.c b/sound/soc/blackfin/bf5xx-sport.c
index 99051ff0954e..a2d40349fcc4 100644
--- a/sound/soc/blackfin/bf5xx-sport.c
+++ b/sound/soc/blackfin/bf5xx-sport.c
@@ -42,8 +42,6 @@
 /* delay between frame sync pulse and first data bit in multichannel mode */
 #define FRAME_DELAY (1<<12)
 
-struct sport_device *sport_handle;
-EXPORT_SYMBOL(sport_handle);
 /* note: multichannel is in units of 8 channels,
  * tdm_count is # channels NOT / 8 ! */
 int sport_set_multichannel(struct sport_device *sport,
@@ -798,86 +796,164 @@ int sport_set_err_callback(struct sport_device *sport,
 }
 EXPORT_SYMBOL(sport_set_err_callback);
 
-struct sport_device *sport_init(struct sport_param *param, unsigned wdsize,
-		unsigned dummy_count, void *private_data)
+static int sport_config_pdev(struct platform_device *pdev, struct sport_param *param)
 {
-	int ret;
+	/* Extract settings from platform data */
+	struct device *dev = &pdev->dev;
+	struct bfin_snd_platform_data *pdata = dev->platform_data;
+	struct resource *res;
+
+	param->num = pdev->id;
+
+	if (!pdata) {
+		dev_err(dev, "no platform_data\n");
+		return -ENODEV;
+	}
+	param->pin_req = pdata->pin_req;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "no MEM resource\n");
+		return -ENODEV;
+	}
+	param->regs = (struct sport_register *)res->start;
+
+	/* first RX, then TX */
+	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (!res) {
+		dev_err(dev, "no rx DMA resource\n");
+		return -ENODEV;
+	}
+	param->dma_rx_chan = res->start;
+
+	res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+	if (!res) {
+		dev_err(dev, "no tx DMA resource\n");
+		return -ENODEV;
+	}
+	param->dma_tx_chan = res->start;
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		dev_err(dev, "no irq resource\n");
+		return -ENODEV;
+	}
+	param->err_irq = res->start;
+
+	return 0;
+}
+
+struct sport_device *sport_init(struct platform_device *pdev,
+	unsigned int wdsize, unsigned int dummy_count, size_t priv_size)
+{
+	struct device *dev = &pdev->dev;
+	struct sport_param param;
 	struct sport_device *sport;
-	pr_debug("%s enter\n", __func__);
-	BUG_ON(param == NULL);
-	BUG_ON(wdsize == 0 || dummy_count == 0);
-	sport = kmalloc(sizeof(struct sport_device), GFP_KERNEL);
-	if (!sport) {
-		pr_err("Failed to allocate for sport device\n");
+	int ret;
+
+	dev_dbg(dev, "%s enter\n", __func__);
+
+	param.wdsize = wdsize;
+	param.dummy_count = dummy_count;
+	BUG_ON(param.wdsize == 0 || param.dummy_count == 0);
+
+	ret = sport_config_pdev(pdev, &param);
+	if (ret)
+		return NULL;
+
+	if (peripheral_request_list(param.pin_req, "soc-audio")) {
+		dev_err(dev, "requesting Peripherals failed\n");
 		return NULL;
 	}
 
-	memset(sport, 0, sizeof(struct sport_device));
-	sport->dma_rx_chan = param->dma_rx_chan;
-	sport->dma_tx_chan = param->dma_tx_chan;
-	sport->err_irq = param->err_irq;
-	sport->regs = param->regs;
-	sport->private_data = private_data;
+	sport = kzalloc(sizeof(*sport), GFP_KERNEL);
+	if (!sport) {
+		dev_err(dev, "failed to allocate for sport device\n");
+		goto __init_err0;
+	}
+
+	sport->num = param.num;
+	sport->dma_rx_chan = param.dma_rx_chan;
+	sport->dma_tx_chan = param.dma_tx_chan;
+	sport->err_irq = param.err_irq;
+	sport->regs = param.regs;
+	sport->pin_req = param.pin_req;
 
 	if (request_dma(sport->dma_rx_chan, "SPORT RX Data") == -EBUSY) {
-		pr_err("Failed to request RX dma %d\n", \
-				sport->dma_rx_chan);
+		dev_err(dev, "failed to request RX dma %d\n", sport->dma_rx_chan);
 		goto __init_err1;
 	}
 	if (set_dma_callback(sport->dma_rx_chan, rx_handler, sport) != 0) {
-		pr_err("Failed to request RX irq %d\n", \
-				sport->dma_rx_chan);
+		dev_err(dev, "failed to request RX irq %d\n", sport->dma_rx_chan);
 		goto __init_err2;
 	}
 
 	if (request_dma(sport->dma_tx_chan, "SPORT TX Data") == -EBUSY) {
-		pr_err("Failed to request TX dma %d\n", \
-				sport->dma_tx_chan);
+		dev_err(dev, "failed to request TX dma %d\n", sport->dma_tx_chan);
 		goto __init_err2;
 	}
 
 	if (set_dma_callback(sport->dma_tx_chan, tx_handler, sport) != 0) {
-		pr_err("Failed to request TX irq %d\n", \
-				sport->dma_tx_chan);
+		dev_err(dev, "failed to request TX irq %d\n", sport->dma_tx_chan);
 		goto __init_err3;
 	}
 
 	if (request_irq(sport->err_irq, err_handler, IRQF_SHARED, "SPORT err",
 			sport) < 0) {
-		pr_err("Failed to request err irq:%d\n", \
-				sport->err_irq);
+		dev_err(dev, "failed to request err irq %d\n", sport->err_irq);
 		goto __init_err3;
 	}
 
-	pr_err("dma rx:%d tx:%d, err irq:%d, regs:%p\n",
+	dev_info(dev, "dma rx:%d tx:%d, err irq:%d, regs:%p\n",
 			sport->dma_rx_chan, sport->dma_tx_chan,
 			sport->err_irq, sport->regs);
 
-	sport->wdsize = wdsize;
-	sport->dummy_count = dummy_count;
+	sport->wdsize = param.wdsize;
+	sport->dummy_count = param.dummy_count;
+
+	sport->private_data = kzalloc(priv_size, GFP_KERNEL);
+	if (!sport->private_data) {
+		dev_err(dev, "could not alloc priv data %zu bytes\n", priv_size);
+		goto __init_err4;
+	}
 
 	if (L1_DATA_A_LENGTH)
-		sport->dummy_buf = l1_data_sram_zalloc(dummy_count * 2);
+		sport->dummy_buf = l1_data_sram_zalloc(param.dummy_count * 2);
 	else
-		sport->dummy_buf = kzalloc(dummy_count * 2, GFP_KERNEL);
+		sport->dummy_buf = kzalloc(param.dummy_count * 2, GFP_KERNEL);
 	if (sport->dummy_buf == NULL) {
-		pr_err("Failed to allocate dummy buffer\n");
-		goto __error;
+		dev_err(dev, "failed to allocate dummy buffer\n");
+		goto __error1;
 	}
 
 	ret = sport_config_rx_dummy(sport);
 	if (ret) {
-		pr_err("Failed to config rx dummy ring\n");
-		goto __error;
+		dev_err(dev, "failed to config rx dummy ring\n");
+		goto __error2;
 	}
 	ret = sport_config_tx_dummy(sport);
 	if (ret) {
-		pr_err("Failed to config tx dummy ring\n");
-		goto __error;
+		dev_err(dev, "failed to config tx dummy ring\n");
+		goto __error3;
 	}
 
+	platform_set_drvdata(pdev, sport);
+
 	return sport;
-__error:
+__error3:
+	if (L1_DATA_A_LENGTH)
+		l1_data_sram_free(sport->dummy_rx_desc);
+	else
+		dma_free_coherent(NULL, 2*sizeof(struct dmasg),
+				sport->dummy_rx_desc, 0);
+__error2:
+	if (L1_DATA_A_LENGTH)
+		l1_data_sram_free(sport->dummy_buf);
+	else
+		kfree(sport->dummy_buf);
+__error1:
+	kfree(sport->private_data);
+__init_err4:
 	free_irq(sport->err_irq, sport);
 __init_err3:
 	free_dma(sport->dma_tx_chan);
@@ -885,6 +961,8 @@ __init_err2:
 	free_dma(sport->dma_rx_chan);
 __init_err1:
 	kfree(sport);
+__init_err0:
+	peripheral_free_list(param.pin_req);
 	return NULL;
 }
 EXPORT_SYMBOL(sport_init);
@@ -917,8 +995,9 @@ void sport_done(struct sport_device *sport)
 	free_dma(sport->dma_tx_chan);
 	free_irq(sport->err_irq, sport);
 
+	kfree(sport->private_data);
+	peripheral_free_list(sport->pin_req);
 	kfree(sport);
-		sport = NULL;
 }
 EXPORT_SYMBOL(sport_done);
 
diff --git a/sound/soc/blackfin/bf5xx-sport.h b/sound/soc/blackfin/bf5xx-sport.h
index a86e8cc0b2d3..5ab60bd613ea 100644
--- a/sound/soc/blackfin/bf5xx-sport.h
+++ b/sound/soc/blackfin/bf5xx-sport.h
@@ -1,5 +1,5 @@
 /*
- * File:         bf5xx_ac97_sport.h
+ * File:         bf5xx_sport.h
  * Based on:
  * Author:       Roy Huang <roy.huang@analog.com>
  *
@@ -33,15 +33,18 @@
 #include <linux/types.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
+#include <linux/platform_device.h>
 #include <asm/dma.h>
 #include <asm/bfin_sport.h>
 
 #define DESC_ELEMENT_COUNT 9
 
 struct sport_device {
+	int num;
 	int dma_rx_chan;
 	int dma_tx_chan;
 	int err_irq;
+	const unsigned short *pin_req;
 	struct sport_register *regs;
 
 	unsigned char *rx_buf;
@@ -103,17 +106,20 @@ struct sport_device {
 	void *private_data;
 };
 
-extern struct sport_device *sport_handle;
-
 struct sport_param {
+	int num;
 	int dma_rx_chan;
 	int dma_tx_chan;
 	int err_irq;
+	const unsigned short *pin_req;
 	struct sport_register *regs;
+	unsigned int wdsize;
+	unsigned int dummy_count;
+	void *private_data;
 };
 
-struct sport_device *sport_init(struct sport_param *param, unsigned wdsize,
-		unsigned dummy_count, void *private_data);
+struct sport_device *sport_init(struct platform_device *pdev,
+	unsigned int wdsize, unsigned int dummy_count, size_t priv_size);
 
 void sport_done(struct sport_device *sport);
 
diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c
index ad28663f5bbd..767e772a815d 100644
--- a/sound/soc/blackfin/bf5xx-ssm2602.c
+++ b/sound/soc/blackfin/bf5xx-ssm2602.c
@@ -44,16 +44,6 @@
 
 static struct snd_soc_card bf5xx_ssm2602;
 
-static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-	pr_debug("%s enter\n", __func__);
-	snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-	return 0;
-}
-
 static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
 {
@@ -109,23 +99,33 @@ static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
 }
 
 static struct snd_soc_ops bf5xx_ssm2602_ops = {
-	.startup = bf5xx_ssm2602_startup,
 	.hw_params = bf5xx_ssm2602_hw_params,
 };
 
-static struct snd_soc_dai_link bf5xx_ssm2602_dai = {
-	.name = "ssm2602",
-	.stream_name = "SSM2602",
-	.cpu_dai_name = "bf5xx-i2s",
-	.codec_dai_name = "ssm2602-hifi",
-	.platform_name = "bf5xx-pcm-audio",
-	.codec_name = "ssm2602-codec.0-001b",
-	.ops = &bf5xx_ssm2602_ops,
+static struct snd_soc_dai_link bf5xx_ssm2602_dai[] = {
+	{
+		.name = "ssm2602",
+		.stream_name = "SSM2602",
+		.cpu_dai_name = "bfin-i2s.0",
+		.codec_dai_name = "ssm2602-hifi",
+		.platform_name = "bfin-i2s-pcm-audio",
+		.codec_name = "ssm2602.0-001b",
+		.ops = &bf5xx_ssm2602_ops,
+	},
+	{
+		.name = "ssm2602",
+		.stream_name = "SSM2602",
+		.cpu_dai_name = "bfin-i2s.1",
+		.codec_dai_name = "ssm2602-hifi",
+		.platform_name = "bfin-i2s-pcm-audio",
+		.codec_name = "ssm2602.0-001b",
+		.ops = &bf5xx_ssm2602_ops,
+	},
 };
 
 static struct snd_soc_card bf5xx_ssm2602 = {
-	.name = "bf5xx_ssm2602",
-	.dai_link = &bf5xx_ssm2602_dai,
+	.name = "bfin-ssm2602",
+	.dai_link = &bf5xx_ssm2602_dai[CONFIG_SND_BF5XX_SPORT_NUM],
 	.num_links = 1,
 };
 
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c
index 74cf759b78a6..07cfc7a9e49a 100644
--- a/sound/soc/blackfin/bf5xx-tdm-pcm.c
+++ b/sound/soc/blackfin/bf5xx-tdm-pcm.c
@@ -154,7 +154,12 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
 
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 {
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+
 	int ret = 0;
 
 	snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
@@ -164,9 +169,14 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 	if (ret < 0)
 		goto out;
 
-	if (sport_handle != NULL)
+	if (sport_handle != NULL) {
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			sport_handle->tx_buf = buf->area;
+		else
+			sport_handle->rx_buf = buf->area;
+
 		runtime->private_data = sport_handle;
-	else {
+	} else {
 		pr_err("sport_handle is NULL\n");
 		ret = -ENODEV;
 	}
@@ -249,11 +259,6 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 	}
 	buf->bytes = size;
 
-	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-		sport_handle->tx_buf = buf->area;
-	else
-		sport_handle->rx_buf = buf->area;
-
 	return 0;
 }
 
@@ -274,8 +279,6 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 		dma_free_coherent(NULL, buf->bytes, buf->area, 0);
 		buf->area = NULL;
 	}
-	if (sport_handle)
-		sport_done(sport_handle);
 }
 
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
@@ -326,7 +329,7 @@ static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
 
 static struct platform_driver bfin_tdm_driver = {
 	.driver = {
-			.name = "bf5xx-tdm-pcm-audio",
+			.name = "bfin-tdm-pcm-audio",
 			.owner = THIS_MODULE,
 	},
 
diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c
index 5515ac9e05c7..a822d1ee1380 100644
--- a/sound/soc/blackfin/bf5xx-tdm.c
+++ b/sound/soc/blackfin/bf5xx-tdm.c
@@ -46,43 +46,6 @@
 #include "bf5xx-sport.h"
 #include "bf5xx-tdm.h"
 
-static struct bf5xx_tdm_port bf5xx_tdm;
-static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
-
-static struct sport_param sport_params[2] = {
-	{
-		.dma_rx_chan    = CH_SPORT0_RX,
-		.dma_tx_chan    = CH_SPORT0_TX,
-		.err_irq        = IRQ_SPORT0_ERROR,
-		.regs           = (struct sport_register *)SPORT0_TCR1,
-	},
-	{
-		.dma_rx_chan    = CH_SPORT1_RX,
-		.dma_tx_chan    = CH_SPORT1_TX,
-		.err_irq        = IRQ_SPORT1_ERROR,
-		.regs           = (struct sport_register *)SPORT1_TCR1,
-	}
-};
-
-/*
- * Setting the TFS pin selector for SPORT 0 based on whether the selected
- * port id F or G. If the port is F then no conflict should exist for the
- * TFS. When Port G is selected and EMAC then there is a conflict between
- * the PHY interrupt line and TFS.  Current settings prevent the conflict
- * by ignoring the TFS pin when Port G is selected. This allows both
- * codecs and EMAC using Port G concurrently.
- */
-#ifdef CONFIG_BF527_SPORT0_PORTG
-#define LOCAL_SPORT0_TFS (0)
-#else
-#define LOCAL_SPORT0_TFS (P_SPORT0_TFS)
-#endif
-
-static u16 sport_req[][7] = { {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
-	P_SPORT0_DRPRI, P_SPORT0_RSCLK, LOCAL_SPORT0_TFS, 0},
-	   {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, P_SPORT1_DRPRI,
-		   P_SPORT1_RSCLK, P_SPORT1_TFS, 0} };
-
 static int bf5xx_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 	unsigned int fmt)
 {
@@ -119,14 +82,16 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params,
 	struct snd_soc_dai *dai)
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+	struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
 	int ret = 0;
 
-	bf5xx_tdm.tcr2 &= ~0x1f;
-	bf5xx_tdm.rcr2 &= ~0x1f;
+	bf5xx_tdm->tcr2 &= ~0x1f;
+	bf5xx_tdm->rcr2 &= ~0x1f;
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S32_LE:
-		bf5xx_tdm.tcr2 |= 31;
-		bf5xx_tdm.rcr2 |= 31;
+		bf5xx_tdm->tcr2 |= 31;
+		bf5xx_tdm->rcr2 |= 31;
 		sport_handle->wdsize = 4;
 		break;
 		/* at present, we only support 32bit transfer */
@@ -136,7 +101,7 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
 		break;
 	}
 
-	if (!bf5xx_tdm.configured) {
+	if (!bf5xx_tdm->configured) {
 		/*
 		 * TX and RX are not independent,they are enabled at the
 		 * same time, even if only one side is running. So, we
@@ -145,21 +110,21 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
 		 *
 		 * CPU DAI:slave mode.
 		 */
-		ret = sport_config_rx(sport_handle, bf5xx_tdm.rcr1,
-			bf5xx_tdm.rcr2, 0, 0);
+		ret = sport_config_rx(sport_handle, bf5xx_tdm->rcr1,
+			bf5xx_tdm->rcr2, 0, 0);
 		if (ret) {
 			pr_err("SPORT is busy!\n");
 			return -EBUSY;
 		}
 
-		ret = sport_config_tx(sport_handle, bf5xx_tdm.tcr1,
-			bf5xx_tdm.tcr2, 0, 0);
+		ret = sport_config_tx(sport_handle, bf5xx_tdm->tcr1,
+			bf5xx_tdm->tcr2, 0, 0);
 		if (ret) {
 			pr_err("SPORT is busy!\n");
 			return -EBUSY;
 		}
 
-		bf5xx_tdm.configured = 1;
+		bf5xx_tdm->configured = 1;
 	}
 
 	return 0;
@@ -168,15 +133,20 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
 static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream,
 	struct snd_soc_dai *dai)
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+	struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
+
 	/* No active stream, SPORT is allowed to be configured again. */
 	if (!dai->active)
-		bf5xx_tdm.configured = 0;
+		bf5xx_tdm->configured = 0;
 }
 
 static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
 		unsigned int tx_num, unsigned int *tx_slot,
 		unsigned int rx_num, unsigned int *rx_slot)
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+	struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
 	int i;
 	unsigned int slot;
 	unsigned int tx_mapped = 0, rx_mapped = 0;
@@ -189,7 +159,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
 		slot = tx_slot[i];
 		if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
 				(!(tx_mapped & (1 << slot)))) {
-			bf5xx_tdm.tx_map[i] = slot;
+			bf5xx_tdm->tx_map[i] = slot;
 			tx_mapped |= 1 << slot;
 		} else
 			return -EINVAL;
@@ -198,7 +168,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
 		slot = rx_slot[i];
 		if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
 				(!(rx_mapped & (1 << slot)))) {
-			bf5xx_tdm.rx_map[i] = slot;
+			bf5xx_tdm->rx_map[i] = slot;
 			rx_mapped |= 1 << slot;
 		} else
 			return -EINVAL;
@@ -212,12 +182,14 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
 {
 	struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
-	if (!dai->active)
-		return 0;
-	if (dai->capture_active)
-		sport_rx_stop(sport);
 	if (dai->playback_active)
 		sport_tx_stop(sport);
+	if (dai->capture_active)
+		sport_rx_stop(sport);
+
+	/* isolate sync/clock pins from codec while sports resume */
+	peripheral_free_list(sport->pin_req);
+
 	return 0;
 }
 
@@ -226,9 +198,6 @@ static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
 	int ret;
 	struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
-	if (!dai->active)
-		return 0;
-
 	ret = sport_set_multichannel(sport, 8, 0xFF, 1);
 	if (ret) {
 		pr_err("SPORT is busy!\n");
@@ -247,6 +216,8 @@ static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
 		ret = -EBUSY;
 	}
 
+	peripheral_request_list(sport->pin_req, "soc-audio");
+
 	return 0;
 }
 
@@ -280,20 +251,14 @@ static struct snd_soc_dai_driver bf5xx_tdm_dai = {
 
 static int __devinit bfin_tdm_probe(struct platform_device *pdev)
 {
-	int ret = 0;
-
-	if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
-		pr_err("Requesting Peripherals failed\n");
-		return -EFAULT;
-	}
+	struct sport_device *sport_handle;
+	int ret;
 
-	/* request DMA for SPORT */
-	sport_handle = sport_init(&sport_params[sport_num], 4, \
-		8 * sizeof(u32), NULL);
-	if (!sport_handle) {
-		peripheral_free_list(&sport_req[sport_num][0]);
+	/* configure SPORT for TDM */
+	sport_handle = sport_init(pdev, 4, 8 * sizeof(u32),
+		sizeof(struct bf5xx_tdm_port));
+	if (!sport_handle)
 		return -ENODEV;
-	}
 
 	/* SPORT works in TDM mode */
 	ret = sport_set_multichannel(sport_handle, 8, 0xFF, 1);
@@ -323,18 +288,19 @@ static int __devinit bfin_tdm_probe(struct platform_device *pdev)
 		goto sport_config_err;
 	}
 
-	sport_handle->private_data = &bf5xx_tdm;
 	return 0;
 
 sport_config_err:
-	peripheral_free_list(&sport_req[sport_num][0]);
+	sport_done(sport_handle);
 	return ret;
 }
 
 static int __devexit bfin_tdm_remove(struct platform_device *pdev)
 {
-	peripheral_free_list(&sport_req[sport_num][0]);
+	struct sport_device *sport_handle = platform_get_drvdata(pdev);
+
 	snd_soc_unregister_dai(&pdev->dev);
+	sport_done(sport_handle);
 
 	return 0;
 }
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
index 06b6981b8d6d..19241576b6b5 100644
--- a/sound/soc/codecs/88pm860x-codec.c
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -120,7 +120,7 @@
  */
 #define PM860X_DAPM_OUTPUT(wname, wevent)	\
 {	.id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \
-	.shift = 0, .invert = 0, .kcontrols = NULL, \
+	.shift = 0, .invert = 0, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD, }
 
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 6943e24a74a1..98175a096df2 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -16,10 +16,11 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_AD1836 if SPI_MASTER
 	select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI
 	select SND_SOC_AD1980 if SND_SOC_AC97_BUS
+	select SND_SOC_AD73311
 	select SND_SOC_ADS117X
-	select SND_SOC_AD73311 if I2C
 	select SND_SOC_AK4104 if SPI_MASTER
 	select SND_SOC_AK4535 if I2C
+	select SND_SOC_AK4641 if I2C
 	select SND_SOC_AK4642 if I2C
 	select SND_SOC_AK4671 if I2C
 	select SND_SOC_ALC5623 if I2C
@@ -33,13 +34,14 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_JZ4740_CODEC if SOC_JZ4740
 	select SND_SOC_LM4857 if I2C
 	select SND_SOC_MAX98088 if I2C
+	select SND_SOC_MAX98095 if I2C
 	select SND_SOC_MAX9850 if I2C
 	select SND_SOC_MAX9877 if I2C
 	select SND_SOC_PCM3008
 	select SND_SOC_SGTL5000 if I2C
 	select SND_SOC_SN95031 if INTEL_SCU_IPC
 	select SND_SOC_SPDIF
-	select SND_SOC_SSM2602 if I2C
+	select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
 	select SND_SOC_TLV320AIC23 if I2C
 	select SND_SOC_TLV320AIC26 if SPI_MASTER
@@ -52,6 +54,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_UDA134X
 	select SND_SOC_UDA1380 if I2C
 	select SND_SOC_WL1273 if MFD_WL1273_CORE
+	select SND_SOC_WM1250_EV1 if I2C
 	select SND_SOC_WM2000 if I2C
 	select SND_SOC_WM8350 if MFD_WM8350
 	select SND_SOC_WM8400 if MFD_WM8400
@@ -72,6 +75,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_WM8900 if I2C
 	select SND_SOC_WM8903 if I2C
 	select SND_SOC_WM8904 if I2C
+	select SND_SOC_WM8915 if I2C
 	select SND_SOC_WM8940 if I2C
 	select SND_SOC_WM8955 if I2C
 	select SND_SOC_WM8960 if I2C
@@ -136,6 +140,9 @@ config SND_SOC_AK4104
 config SND_SOC_AK4535
 	tristate
 
+config SND_SOC_AK4641
+	tristate
+
 config SND_SOC_AK4642
 	tristate
 
@@ -187,6 +194,9 @@ config SND_SOC_DMIC
 config SND_SOC_MAX98088
        tristate
 
+config SND_SOC_MAX98095
+       tristate
+
 config SND_SOC_MAX9850
 	tristate
 
@@ -241,6 +251,9 @@ config SND_SOC_UDA1380
 config SND_SOC_WL1273
 	tristate
 
+config SND_SOC_WM1250_EV1
+	tristate
+
 config SND_SOC_WM8350
 	tristate
 
@@ -298,6 +311,9 @@ config SND_SOC_WM8903
 config SND_SOC_WM8904
 	tristate
 
+config SND_SOC_WM8915
+	tristate
+
 config SND_SOC_WM8940
         tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 379bc55f0723..fd8558406ef0 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -7,6 +7,7 @@ snd-soc-ad73311-objs := ad73311.o
 snd-soc-ads117x-objs := ads117x.o
 snd-soc-ak4104-objs := ak4104.o
 snd-soc-ak4535-objs := ak4535.o
+snd-soc-ak4641-objs := ak4641.o
 snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
 snd-soc-cq93vc-objs := cq93vc.o
@@ -19,6 +20,7 @@ snd-soc-dfbmcs320-objs := dfbmcs320.o
 snd-soc-dmic-objs := dmic.o
 snd-soc-l3-objs := l3.o
 snd-soc-max98088-objs := max98088.o
+snd-soc-max98095-objs := max98095.o
 snd-soc-max9850-objs := max9850.o
 snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-sgtl5000-objs := sgtl5000.o
@@ -37,6 +39,7 @@ snd-soc-twl6040-objs := twl6040.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wl1273-objs := wl1273.o
+snd-soc-wm1250-ev1-objs := wm1250-ev1.o
 snd-soc-wm8350-objs := wm8350.o
 snd-soc-wm8400-objs := wm8400.o
 snd-soc-wm8510-objs := wm8510.o
@@ -56,6 +59,7 @@ snd-soc-wm8804-objs := wm8804.o
 snd-soc-wm8900-objs := wm8900.o
 snd-soc-wm8903-objs := wm8903.o
 snd-soc-wm8904-objs := wm8904.o
+snd-soc-wm8915-objs := wm8915.o
 snd-soc-wm8940-objs := wm8940.o
 snd-soc-wm8955-objs := wm8955.o
 snd-soc-wm8960-objs := wm8960.o
@@ -69,7 +73,7 @@ snd-soc-wm8988-objs := wm8988.o
 snd-soc-wm8990-objs := wm8990.o
 snd-soc-wm8991-objs := wm8991.o
 snd-soc-wm8993-objs := wm8993.o
-snd-soc-wm8994-objs := wm8994.o wm8994-tables.o
+snd-soc-wm8994-objs := wm8994.o wm8994-tables.o wm8958-dsp2.o
 snd-soc-wm8995-objs := wm8995.o
 snd-soc-wm9081-objs := wm9081.o
 snd-soc-wm9705-objs := wm9705.o
@@ -94,6 +98,7 @@ obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
 obj-$(CONFIG_SND_SOC_ADS117X)	+= snd-soc-ads117x.o
 obj-$(CONFIG_SND_SOC_AK4104)	+= snd-soc-ak4104.o
 obj-$(CONFIG_SND_SOC_AK4535)	+= snd-soc-ak4535.o
+obj-$(CONFIG_SND_SOC_AK4641)	+= snd-soc-ak4641.o
 obj-$(CONFIG_SND_SOC_AK4642)	+= snd-soc-ak4642.o
 obj-$(CONFIG_SND_SOC_AK4671)	+= snd-soc-ak4671.o
 obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
@@ -108,6 +113,7 @@ obj-$(CONFIG_SND_SOC_DMIC)	+= snd-soc-dmic.o
 obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)	+= snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_MAX98088)	+= snd-soc-max98088.o
+obj-$(CONFIG_SND_SOC_MAX98095)	+= snd-soc-max98095.o
 obj-$(CONFIG_SND_SOC_MAX9850)	+= snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
@@ -125,6 +131,7 @@ obj-$(CONFIG_SND_SOC_TWL6040)	+= snd-soc-twl6040.o
 obj-$(CONFIG_SND_SOC_UDA134X)	+= snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)	+= snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WL1273)	+= snd-soc-wl1273.o
+obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
 obj-$(CONFIG_SND_SOC_WM8350)	+= snd-soc-wm8350.o
 obj-$(CONFIG_SND_SOC_WM8400)	+= snd-soc-wm8400.o
 obj-$(CONFIG_SND_SOC_WM8510)	+= snd-soc-wm8510.o
@@ -144,6 +151,7 @@ obj-$(CONFIG_SND_SOC_WM8804)	+= snd-soc-wm8804.o
 obj-$(CONFIG_SND_SOC_WM8900)	+= snd-soc-wm8900.o
 obj-$(CONFIG_SND_SOC_WM8903)	+= snd-soc-wm8903.o
 obj-$(CONFIG_SND_SOC_WM8904)	+= snd-soc-wm8904.o
+obj-$(CONFIG_SND_SOC_WM8915)	+= snd-soc-wm8915.o
 obj-$(CONFIG_SND_SOC_WM8940)	+= snd-soc-wm8940.o
 obj-$(CONFIG_SND_SOC_WM8955)	+= snd-soc-wm8955.o
 obj-$(CONFIG_SND_SOC_WM8960)	+= snd-soc-wm8960.o
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index da46479bfcfa..2374ca5ffe68 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -23,8 +23,7 @@
 
 /* codec private data */
 struct ad193x_priv {
-	enum snd_soc_control_type bus_type;
-	void *control_data;
+	enum snd_soc_control_type control_type;
 	int sysclk;
 };
 
@@ -354,14 +353,12 @@ static int ad193x_probe(struct snd_soc_codec *codec)
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	int ret;
 
-	codec->control_data = ad193x->control_data;
-	if (ad193x->bus_type == SND_SOC_I2C)
-		ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->bus_type);
+	if (ad193x->control_type == SND_SOC_I2C)
+		ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->control_type);
 	else
-		ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->bus_type);
+		ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->control_type);
 	if (ret < 0) {
-		dev_err(codec->dev, "failed to set cache I/O: %d\n",
-				ret);
+		dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
 		return ret;
 	}
 
@@ -408,8 +405,7 @@ static int __devinit ad193x_spi_probe(struct spi_device *spi)
 		return -ENOMEM;
 
 	spi_set_drvdata(spi, ad193x);
-	ad193x->control_data = spi;
-	ad193x->bus_type = SND_SOC_SPI;
+	ad193x->control_type = SND_SOC_SPI;
 
 	ret = snd_soc_register_codec(&spi->dev,
 			&soc_codec_dev_ad193x, &ad193x_dai, 1);
@@ -427,7 +423,7 @@ static int __devexit ad193x_spi_remove(struct spi_device *spi)
 
 static struct spi_driver ad193x_spi_driver = {
 	.driver = {
-		.name	= "ad193x-codec",
+		.name	= "ad193x",
 		.owner	= THIS_MODULE,
 	},
 	.probe		= ad193x_spi_probe,
@@ -454,8 +450,7 @@ static int __devinit ad193x_i2c_probe(struct i2c_client *client,
 		return -ENOMEM;
 
 	i2c_set_clientdata(client, ad193x);
-	ad193x->control_data = client;
-	ad193x->bus_type = SND_SOC_I2C;
+	ad193x->control_type = SND_SOC_I2C;
 
 	ret =  snd_soc_register_codec(&client->dev,
 			&soc_codec_dev_ad193x, &ad193x_dai, 1);
@@ -473,7 +468,7 @@ static int __devexit ad193x_i2c_remove(struct i2c_client *client)
 
 static struct i2c_driver ad193x_i2c_driver = {
 	.driver = {
-		.name = "ad193x-codec",
+		.name = "ad193x",
 	},
 	.probe    = ad193x_i2c_probe,
 	.remove   = __devexit_p(ad193x_i2c_remove),
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index 34cb51ef2156..923b364a3e41 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -266,7 +266,7 @@ static int __devexit ad1980_remove(struct platform_device *pdev)
 
 static struct platform_driver ad1980_codec_driver = {
 	.driver = {
-			.name = "ad1980-codec",
+			.name = "ad1980",
 			.owner = THIS_MODULE,
 	},
 
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c
index de799cd1ba72..8d793e993e9a 100644
--- a/sound/soc/codecs/ad73311.c
+++ b/sound/soc/codecs/ad73311.c
@@ -55,7 +55,7 @@ static int __devexit ad73311_remove(struct platform_device *pdev)
 
 static struct platform_driver ad73311_codec_driver = {
 	.driver = {
-			.name = "ad73311-codec",
+			.name = "ad73311",
 			.owner = THIS_MODULE,
 	},
 
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 8b38739c88f8..e1a214ee757f 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -230,7 +230,7 @@ static const struct snd_soc_dapm_widget ak4535_dapm_widgets[] = {
 	SND_SOC_DAPM_INPUT("AIN"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route ak4535_audio_map[] = {
 	/*stereo mixer */
 	{"Stereo Mixer", "Playback Switch", "DAC"},
 	{"Stereo Mixer", "Mic Sidetone Switch", "Mic"},
@@ -287,17 +287,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	{"Input Mixer", "Aux Capture Switch", "Aux In"},
 };
 
-static int ak4535_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, ak4535_dapm_widgets,
-				  ARRAY_SIZE(ak4535_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-	return 0;
-}
-
 static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 	int clk_id, unsigned int freq, int dir)
 {
@@ -457,8 +446,6 @@ static int ak4535_probe(struct snd_soc_codec *codec)
 
 	snd_soc_add_controls(codec, ak4535_snd_controls,
 				ARRAY_SIZE(ak4535_snd_controls));
-	ak4535_add_widgets(codec);
-
 	return 0;
 }
 
@@ -480,6 +467,10 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
 	.reg_cache_size = ARRAY_SIZE(ak4535_reg),
 	.reg_word_size = sizeof(u8),
 	.reg_cache_default = ak4535_reg,
+	.dapm_widgets = ak4535_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets),
+	.dapm_routes = ak4535_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(ak4535_audio_map),
 };
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
new file mode 100644
index 000000000000..ed96f247c2da
--- /dev/null
+++ b/sound/soc/codecs/ak4641.c
@@ -0,0 +1,664 @@
+/*
+ * ak4641.c  --  AK4641 ALSA Soc Audio driver
+ *
+ * Copyright (C) 2008 Harald Welte <laforge@gnufiish.org>
+ * Copyright (C) 2011 Dmitry Artamonow <mad_soft@inbox.ru>
+ *
+ * Based on ak4535.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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/ak4641.h>
+
+#include "ak4641.h"
+
+/* codec private data */
+struct ak4641_priv {
+	struct snd_soc_codec *codec;
+	unsigned int sysclk;
+	int deemph;
+	int playback_fs;
+};
+
+/*
+ * ak4641 register cache
+ */
+static const u8 ak4641_reg[AK4641_CACHEREGNUM] = {
+	0x00, 0x80, 0x00, 0x80,
+	0x02, 0x00, 0x11, 0x05,
+	0x00, 0x00, 0x36, 0x10,
+	0x00, 0x00, 0x57, 0x00,
+	0x88, 0x88, 0x08, 0x08
+};
+
+static const int deemph_settings[] = {44100, 0, 48000, 32000};
+
+static int ak4641_set_deemph(struct snd_soc_codec *codec)
+{
+	struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
+	int i, best = 0;
+
+	for (i = 0 ; i < ARRAY_SIZE(deemph_settings); i++) {
+		/* if deemphasis is on, select the nearest available rate */
+		if (ak4641->deemph && deemph_settings[i] != 0 &&
+		    abs(deemph_settings[i] - ak4641->playback_fs) <
+		    abs(deemph_settings[best] - ak4641->playback_fs))
+			best = i;
+
+		if (!ak4641->deemph && deemph_settings[i] == 0)
+			best = i;
+	}
+
+	dev_dbg(codec->dev, "Set deemphasis %d\n", best);
+
+	return snd_soc_update_bits(codec, AK4641_DAC, 0x3, best);
+}
+
+static int ak4641_put_deemph(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
+	int deemph = ucontrol->value.enumerated.item[0];
+
+	if (deemph > 1)
+		return -EINVAL;
+
+	ak4641->deemph = deemph;
+
+	return ak4641_set_deemph(codec);
+}
+
+static int ak4641_get_deemph(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.enumerated.item[0] = ak4641->deemph;
+	return 0;
+};
+
+static const char *ak4641_mono_out[] = {"(L + R)/2", "Hi-Z"};
+static const char *ak4641_hp_out[] = {"Stereo", "Mono"};
+static const char *ak4641_mic_select[] = {"Internal", "External"};
+static const char *ak4641_mic_or_dac[] = {"Microphone", "Voice DAC"};
+
+
+static const DECLARE_TLV_DB_SCALE(mono_gain_tlv, -1700, 2300, 0);
+static const DECLARE_TLV_DB_SCALE(mic_boost_tlv, 0, 2000, 0);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1050, 150, 0);
+static const DECLARE_TLV_DB_SCALE(master_tlv, -12750, 50, 0);
+static const DECLARE_TLV_DB_SCALE(mic_stereo_sidetone_tlv, -2700, 300, 0);
+static const DECLARE_TLV_DB_SCALE(mic_mono_sidetone_tlv, -400, 400, 0);
+static const DECLARE_TLV_DB_SCALE(capture_tlv, -800, 50, 0);
+static const DECLARE_TLV_DB_SCALE(alc_tlv, -800, 50, 0);
+static const DECLARE_TLV_DB_SCALE(aux_in_tlv, -2100, 300, 0);
+
+
+static const struct soc_enum ak4641_mono_out_enum =
+	SOC_ENUM_SINGLE(AK4641_SIG1, 6, 2, ak4641_mono_out);
+static const struct soc_enum ak4641_hp_out_enum =
+	SOC_ENUM_SINGLE(AK4641_MODE2, 2, 2, ak4641_hp_out);
+static const struct soc_enum ak4641_mic_select_enum =
+	SOC_ENUM_SINGLE(AK4641_MIC, 1, 2, ak4641_mic_select);
+static const struct soc_enum ak4641_mic_or_dac_enum =
+	SOC_ENUM_SINGLE(AK4641_BTIF, 4, 2, ak4641_mic_or_dac);
+
+static const struct snd_kcontrol_new ak4641_snd_controls[] = {
+	SOC_ENUM("Mono 1 Output", ak4641_mono_out_enum),
+	SOC_SINGLE_TLV("Mono 1 Gain Volume", AK4641_SIG1, 7, 1, 1,
+							mono_gain_tlv),
+	SOC_ENUM("Headphone Output", ak4641_hp_out_enum),
+	SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0,
+					ak4641_get_deemph, ak4641_put_deemph),
+
+	SOC_SINGLE_TLV("Mic Boost Volume", AK4641_MIC, 0, 1, 0, mic_boost_tlv),
+
+	SOC_SINGLE("ALC Operation Time", AK4641_TIMER, 0, 3, 0),
+	SOC_SINGLE("ALC Recovery Time", AK4641_TIMER, 2, 3, 0),
+	SOC_SINGLE("ALC ZC Time", AK4641_TIMER, 4, 3, 0),
+
+	SOC_SINGLE("ALC 1 Switch", AK4641_ALC1, 5, 1, 0),
+
+	SOC_SINGLE_TLV("ALC Volume", AK4641_ALC2, 0, 71, 0, alc_tlv),
+	SOC_SINGLE("Left Out Enable Switch", AK4641_SIG2, 1, 1, 0),
+	SOC_SINGLE("Right Out Enable Switch", AK4641_SIG2, 0, 1, 0),
+
+	SOC_SINGLE_TLV("Capture Volume", AK4641_PGA, 0, 71, 0, capture_tlv),
+
+	SOC_DOUBLE_R_TLV("Master Playback Volume", AK4641_LATT,
+				AK4641_RATT, 0, 255, 1, master_tlv),
+
+	SOC_SINGLE_TLV("AUX In Volume", AK4641_VOL, 0, 15, 0, aux_in_tlv),
+
+	SOC_SINGLE("Equalizer Switch", AK4641_DAC, 2, 1, 0),
+	SOC_SINGLE_TLV("EQ1 100 Hz Volume", AK4641_EQLO, 0, 15, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ2 250 Hz Volume", AK4641_EQLO, 4, 15, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ3 1 kHz Volume", AK4641_EQMID, 0, 15, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ4 3.5 kHz Volume", AK4641_EQMID, 4, 15, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ5 10 kHz Volume", AK4641_EQHI, 0, 15, 1, eq_tlv),
+};
+
+/* Mono 1 Mixer */
+static const struct snd_kcontrol_new ak4641_mono1_mixer_controls[] = {
+	SOC_DAPM_SINGLE_TLV("Mic Mono Sidetone Volume", AK4641_VOL, 7, 1, 0,
+						mic_mono_sidetone_tlv),
+	SOC_DAPM_SINGLE("Mic Mono Sidetone Switch", AK4641_SIG1, 4, 1, 0),
+	SOC_DAPM_SINGLE("Mono Playback Switch", AK4641_SIG1, 5, 1, 0),
+};
+
+/* Stereo Mixer */
+static const struct snd_kcontrol_new ak4641_stereo_mixer_controls[] = {
+	SOC_DAPM_SINGLE_TLV("Mic Sidetone Volume", AK4641_VOL, 4, 7, 0,
+						mic_stereo_sidetone_tlv),
+	SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4641_SIG2, 4, 1, 0),
+	SOC_DAPM_SINGLE("Playback Switch", AK4641_SIG2, 7, 1, 0),
+	SOC_DAPM_SINGLE("Aux Bypass Switch", AK4641_SIG2, 5, 1, 0),
+};
+
+/* Input Mixer */
+static const struct snd_kcontrol_new ak4641_input_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Mic Capture Switch", AK4641_MIC, 2, 1, 0),
+	SOC_DAPM_SINGLE("Aux Capture Switch", AK4641_MIC, 5, 1, 0),
+};
+
+/* Mic mux */
+static const struct snd_kcontrol_new ak4641_mic_mux_control =
+	SOC_DAPM_ENUM("Mic Select", ak4641_mic_select_enum);
+
+/* Input mux */
+static const struct snd_kcontrol_new ak4641_input_mux_control =
+	SOC_DAPM_ENUM("Input Select", ak4641_mic_or_dac_enum);
+
+/* mono 2 switch */
+static const struct snd_kcontrol_new ak4641_mono2_control =
+	SOC_DAPM_SINGLE("Switch", AK4641_SIG1, 0, 1, 0);
+
+/* ak4641 dapm widgets */
+static const struct snd_soc_dapm_widget ak4641_dapm_widgets[] = {
+	SND_SOC_DAPM_MIXER("Stereo Mixer", SND_SOC_NOPM, 0, 0,
+		&ak4641_stereo_mixer_controls[0],
+		ARRAY_SIZE(ak4641_stereo_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Mono1 Mixer", SND_SOC_NOPM, 0, 0,
+		&ak4641_mono1_mixer_controls[0],
+		ARRAY_SIZE(ak4641_mono1_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0,
+		&ak4641_input_mixer_controls[0],
+		ARRAY_SIZE(ak4641_input_mixer_controls)),
+	SND_SOC_DAPM_MUX("Mic Mux", SND_SOC_NOPM, 0, 0,
+		&ak4641_mic_mux_control),
+	SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
+		&ak4641_input_mux_control),
+	SND_SOC_DAPM_SWITCH("Mono 2 Enable", SND_SOC_NOPM, 0, 0,
+		&ak4641_mono2_control),
+
+	SND_SOC_DAPM_OUTPUT("LOUT"),
+	SND_SOC_DAPM_OUTPUT("ROUT"),
+	SND_SOC_DAPM_OUTPUT("MOUT1"),
+	SND_SOC_DAPM_OUTPUT("MOUT2"),
+	SND_SOC_DAPM_OUTPUT("MICOUT"),
+
+	SND_SOC_DAPM_ADC("ADC", "HiFi Capture", AK4641_PM1, 0, 0),
+	SND_SOC_DAPM_PGA("Mic", AK4641_PM1, 1, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("AUX In", AK4641_PM1, 2, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mono Out", AK4641_PM1, 3, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Line Out", AK4641_PM1, 4, 0, NULL, 0),
+
+	SND_SOC_DAPM_DAC("DAC", "HiFi Playback", AK4641_PM2, 0, 0),
+	SND_SOC_DAPM_PGA("Mono Out 2", AK4641_PM2, 3, 0, NULL, 0),
+
+	SND_SOC_DAPM_ADC("Voice ADC", "Voice Capture", AK4641_BTIF, 0, 0),
+	SND_SOC_DAPM_ADC("Voice DAC", "Voice Playback", AK4641_BTIF, 1, 0),
+
+	SND_SOC_DAPM_MICBIAS("Mic Int Bias", AK4641_MIC, 3, 0),
+	SND_SOC_DAPM_MICBIAS("Mic Ext Bias", AK4641_MIC, 4, 0),
+
+	SND_SOC_DAPM_INPUT("MICIN"),
+	SND_SOC_DAPM_INPUT("MICEXT"),
+	SND_SOC_DAPM_INPUT("AUX"),
+	SND_SOC_DAPM_INPUT("AIN"),
+};
+
+static const struct snd_soc_dapm_route ak4641_audio_map[] = {
+	/* Stereo Mixer */
+	{"Stereo Mixer", "Playback Switch", "DAC"},
+	{"Stereo Mixer", "Mic Sidetone Switch", "Input Mux"},
+	{"Stereo Mixer", "Aux Bypass Switch", "AUX In"},
+
+	/* Mono 1 Mixer */
+	{"Mono1 Mixer", "Mic Mono Sidetone Switch", "Input Mux"},
+	{"Mono1 Mixer", "Mono Playback Switch", "DAC"},
+
+	/* Mic */
+	{"Mic", NULL, "AIN"},
+	{"Mic Mux", "Internal", "Mic Int Bias"},
+	{"Mic Mux", "External", "Mic Ext Bias"},
+	{"Mic Int Bias", NULL, "MICIN"},
+	{"Mic Ext Bias", NULL, "MICEXT"},
+	{"MICOUT", NULL, "Mic Mux"},
+
+	/* Input Mux */
+	{"Input Mux", "Microphone", "Mic"},
+	{"Input Mux", "Voice DAC", "Voice DAC"},
+
+	/* Line Out */
+	{"LOUT", NULL, "Line Out"},
+	{"ROUT", NULL, "Line Out"},
+	{"Line Out", NULL, "Stereo Mixer"},
+
+	/* Mono 1 Out */
+	{"MOUT1", NULL, "Mono Out"},
+	{"Mono Out", NULL, "Mono1 Mixer"},
+
+	/* Mono 2 Out */
+	{"MOUT2", NULL, "Mono 2 Enable"},
+	{"Mono 2 Enable", "Switch", "Mono Out 2"},
+	{"Mono Out 2", NULL, "Stereo Mixer"},
+
+	{"Voice ADC", NULL, "Mono 2 Enable"},
+
+	/* Aux In */
+	{"AUX In", NULL, "AUX"},
+
+	/* ADC */
+	{"ADC", NULL, "Input Mixer"},
+	{"Input Mixer", "Mic Capture Switch", "Mic"},
+	{"Input Mixer", "Aux Capture Switch", "AUX In"},
+};
+
+static int ak4641_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;
+	struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
+
+	ak4641->sysclk = freq;
+	return 0;
+}
+
+static int ak4641_i2s_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
+	int rate = params_rate(params), fs = 256;
+	u8 mode2;
+
+	if (rate)
+		fs = ak4641->sysclk / rate;
+	else
+		return -EINVAL;
+
+	/* set fs */
+	switch (fs) {
+	case 1024:
+		mode2 = (0x2 << 5);
+		break;
+	case 512:
+		mode2 = (0x1 << 5);
+		break;
+	case 256:
+		mode2 = (0x0 << 5);
+		break;
+	default:
+		dev_err(codec->dev, "Error: unsupported fs=%d\n", fs);
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, AK4641_MODE2, (0x3 << 5), mode2);
+
+	/* Update de-emphasis filter for the new rate */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ak4641->playback_fs = rate;
+		ak4641_set_deemph(codec);
+	};
+
+	return 0;
+}
+
+static int ak4641_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
+				  unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u8 btif;
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		btif = (0x3 << 5);
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		btif = (0x2 << 5);
+		break;
+	case SND_SOC_DAIFMT_DSP_A:	/* MSB after FRM */
+		btif = (0x0 << 5);
+		break;
+	case SND_SOC_DAIFMT_DSP_B:	/* MSB during FRM */
+		btif = (0x1 << 5);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return snd_soc_update_bits(codec, AK4641_BTIF, (0x3 << 5), btif);
+}
+
+static int ak4641_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u8 mode1 = 0;
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		mode1 = 0x02;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		mode1 = 0x01;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return snd_soc_write(codec, AK4641_MODE1, mode1);
+}
+
+static int ak4641_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+
+	return snd_soc_update_bits(codec, AK4641_DAC, 0x20, mute ? 0x20 : 0);
+}
+
+static int ak4641_set_bias_level(struct snd_soc_codec *codec,
+	enum snd_soc_bias_level level)
+{
+	struct ak4641_platform_data *pdata = codec->dev->platform_data;
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* unmute */
+		snd_soc_update_bits(codec, AK4641_DAC, 0x20, 0);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		/* mute */
+		snd_soc_update_bits(codec, AK4641_DAC, 0x20, 0x20);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			if (pdata && gpio_is_valid(pdata->gpio_power))
+				gpio_set_value(pdata->gpio_power, 1);
+			mdelay(1);
+			if (pdata && gpio_is_valid(pdata->gpio_npdn))
+				gpio_set_value(pdata->gpio_npdn, 1);
+			mdelay(1);
+
+			ret = snd_soc_cache_sync(codec);
+			if (ret) {
+				dev_err(codec->dev,
+					"Failed to sync cache: %d\n", ret);
+				return ret;
+			}
+		}
+		snd_soc_update_bits(codec, AK4641_PM1, 0x80, 0x80);
+		snd_soc_update_bits(codec, AK4641_PM2, 0x80, 0);
+		break;
+	case SND_SOC_BIAS_OFF:
+		snd_soc_update_bits(codec, AK4641_PM1, 0x80, 0);
+		if (pdata && gpio_is_valid(pdata->gpio_npdn))
+			gpio_set_value(pdata->gpio_npdn, 0);
+		if (pdata && gpio_is_valid(pdata->gpio_power))
+			gpio_set_value(pdata->gpio_power, 0);
+		codec->cache_sync = 1;
+		break;
+	}
+	codec->dapm.bias_level = level;
+	return 0;
+}
+
+#define AK4641_RATES	(SNDRV_PCM_RATE_8000_48000)
+#define AK4641_RATES_BT (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+			 SNDRV_PCM_RATE_16000)
+#define AK4641_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE)
+
+static struct snd_soc_dai_ops ak4641_i2s_dai_ops = {
+	.hw_params    = ak4641_i2s_hw_params,
+	.set_fmt      = ak4641_i2s_set_dai_fmt,
+	.digital_mute = ak4641_mute,
+	.set_sysclk   = ak4641_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_ops ak4641_pcm_dai_ops = {
+	.hw_params    = NULL, /* rates are controlled by BT chip */
+	.set_fmt      = ak4641_pcm_set_dai_fmt,
+	.digital_mute = ak4641_mute,
+	.set_sysclk   = ak4641_set_dai_sysclk,
+};
+
+struct snd_soc_dai_driver ak4641_dai[] = {
+{
+	.name = "ak4641-hifi",
+	.id = 1,
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = AK4641_RATES,
+		.formats = AK4641_FORMATS,
+	},
+	.capture = {
+		.stream_name = "HiFi Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = AK4641_RATES,
+		.formats = AK4641_FORMATS,
+	},
+	.ops = &ak4641_i2s_dai_ops,
+	.symmetric_rates = 1,
+},
+{
+	.name = "ak4641-voice",
+	.id = 1,
+	.playback = {
+		.stream_name = "Voice Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = AK4641_RATES_BT,
+		.formats = AK4641_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Voice Capture",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = AK4641_RATES_BT,
+		.formats = AK4641_FORMATS,
+	},
+	.ops = &ak4641_pcm_dai_ops,
+	.symmetric_rates = 1,
+},
+};
+
+static int ak4641_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+	ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int ak4641_resume(struct snd_soc_codec *codec)
+{
+	ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	return 0;
+}
+
+static int ak4641_probe(struct snd_soc_codec *codec)
+{
+	struct ak4641_platform_data *pdata = codec->dev->platform_data;
+	int ret;
+
+
+	if (pdata) {
+		if (gpio_is_valid(pdata->gpio_power)) {
+			ret = gpio_request_one(pdata->gpio_power,
+					GPIOF_OUT_INIT_LOW, "ak4641 power");
+			if (ret)
+				goto err_out;
+		}
+		if (gpio_is_valid(pdata->gpio_npdn)) {
+			ret = gpio_request_one(pdata->gpio_npdn,
+					GPIOF_OUT_INIT_LOW, "ak4641 npdn");
+			if (ret)
+				goto err_gpio;
+
+			udelay(1); /* > 150 ns */
+			gpio_set_value(pdata->gpio_npdn, 1);
+		}
+	}
+
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		goto err_register;
+	}
+
+	/* power on device */
+	ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	return 0;
+
+err_register:
+	if (pdata) {
+		if (gpio_is_valid(pdata->gpio_power))
+			gpio_set_value(pdata->gpio_power, 0);
+		if (gpio_is_valid(pdata->gpio_npdn))
+			gpio_free(pdata->gpio_npdn);
+	}
+err_gpio:
+	if (pdata && gpio_is_valid(pdata->gpio_power))
+		gpio_free(pdata->gpio_power);
+err_out:
+	return ret;
+}
+
+static int ak4641_remove(struct snd_soc_codec *codec)
+{
+	struct ak4641_platform_data *pdata = codec->dev->platform_data;
+
+	ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	if (pdata) {
+		if (gpio_is_valid(pdata->gpio_power)) {
+			gpio_set_value(pdata->gpio_power, 0);
+			gpio_free(pdata->gpio_power);
+		}
+		if (gpio_is_valid(pdata->gpio_npdn))
+			gpio_free(pdata->gpio_npdn);
+	}
+	return 0;
+}
+
+
+static struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
+	.probe			= ak4641_probe,
+	.remove			= ak4641_remove,
+	.suspend		= ak4641_suspend,
+	.resume			= ak4641_resume,
+	.controls		= ak4641_snd_controls,
+	.num_controls		= ARRAY_SIZE(ak4641_snd_controls),
+	.dapm_widgets		= ak4641_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak4641_dapm_widgets),
+	.dapm_routes		= ak4641_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(ak4641_audio_map),
+	.set_bias_level		= ak4641_set_bias_level,
+	.reg_cache_size		= ARRAY_SIZE(ak4641_reg),
+	.reg_word_size		= sizeof(u8),
+	.reg_cache_default	= ak4641_reg,
+	.reg_cache_step		= 1,
+};
+
+
+static int __devinit ak4641_i2c_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
+{
+	struct ak4641_priv *ak4641;
+	int ret;
+
+	ak4641 = kzalloc(sizeof(struct ak4641_priv), GFP_KERNEL);
+	if (!ak4641)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, ak4641);
+
+	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_ak4641,
+				ak4641_dai, ARRAY_SIZE(ak4641_dai));
+	if (ret < 0)
+		kfree(ak4641);
+
+	return ret;
+}
+
+static int __devexit ak4641_i2c_remove(struct i2c_client *i2c)
+{
+	snd_soc_unregister_codec(&i2c->dev);
+	kfree(i2c_get_clientdata(i2c));
+	return 0;
+}
+
+static const struct i2c_device_id ak4641_i2c_id[] = {
+	{ "ak4641", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ak4641_i2c_id);
+
+static struct i2c_driver ak4641_i2c_driver = {
+	.driver = {
+		.name = "ak4641",
+		.owner = THIS_MODULE,
+	},
+	.probe =    ak4641_i2c_probe,
+	.remove =   __devexit_p(ak4641_i2c_remove),
+	.id_table = ak4641_i2c_id,
+};
+
+static int __init ak4641_modinit(void)
+{
+	int ret;
+
+	ret = i2c_add_driver(&ak4641_i2c_driver);
+	if (ret != 0)
+		pr_err("Failed to register AK4641 I2C driver: %d\n", ret);
+
+	return ret;
+}
+module_init(ak4641_modinit);
+
+static void __exit ak4641_exit(void)
+{
+	i2c_del_driver(&ak4641_i2c_driver);
+}
+module_exit(ak4641_exit);
+
+MODULE_DESCRIPTION("SoC AK4641 driver");
+MODULE_AUTHOR("Harald Welte <laforge@gnufiish.org>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ak4641.h b/sound/soc/codecs/ak4641.h
new file mode 100644
index 000000000000..4a263248efea
--- /dev/null
+++ b/sound/soc/codecs/ak4641.h
@@ -0,0 +1,47 @@
+/*
+ * ak4641.h  --  AK4641 SoC Audio driver
+ *
+ * Copyright 2008 Harald Welte <laforge@gnufiish.org>
+ *
+ * Based on ak4535.h
+ *
+ * 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 _AK4641_H
+#define _AK4641_H
+
+/* AK4641 register space */
+
+#define AK4641_PM1		0x00
+#define AK4641_PM2		0x01
+#define AK4641_SIG1		0x02
+#define AK4641_SIG2		0x03
+#define AK4641_MODE1		0x04
+#define AK4641_MODE2		0x05
+#define AK4641_DAC		0x06
+#define AK4641_MIC		0x07
+#define AK4641_TIMER		0x08
+#define AK4641_ALC1		0x09
+#define AK4641_ALC2		0x0a
+#define AK4641_PGA		0x0b
+#define AK4641_LATT		0x0c
+#define AK4641_RATT		0x0d
+#define AK4641_VOL		0x0e
+#define AK4641_STATUS		0x0f
+#define AK4641_EQLO		0x10
+#define AK4641_EQMID		0x11
+#define AK4641_EQHI		0x12
+#define AK4641_BTIF		0x13
+
+#define AK4641_CACHEREGNUM	0x14
+
+
+
+#define AK4641_DAI_HIFI		0
+#define AK4641_DAI_VOICE	1
+
+
+#endif
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
index 2ec75abfa3e9..88b29f8c748b 100644
--- a/sound/soc/codecs/ak4671.c
+++ b/sound/soc/codecs/ak4671.c
@@ -352,7 +352,7 @@ static const struct snd_soc_dapm_widget ak4671_dapm_widgets[] = {
 	SND_SOC_DAPM_SUPPLY("PMPLL", AK4671_PLL_MODE_SELECT1, 0, 0, NULL, 0),
 };
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route ak4671_intercon[] = {
 	{"DAC Left", "NULL", "PMPLL"},
 	{"DAC Right", "NULL", "PMPLL"},
 	{"ADC Left", "NULL", "PMPLL"},
@@ -433,17 +433,6 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"ROUT3 Mixer", "RINS4", "RIN4 Mixing Circuit"},
 };
 
-static int ak4671_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, ak4671_dapm_widgets,
-				  ARRAY_SIZE(ak4671_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-	return 0;
-}
-
 static int ak4671_hw_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params,
 		struct snd_soc_dai *dai)
@@ -650,7 +639,6 @@ static int ak4671_probe(struct snd_soc_codec *codec)
 
 	snd_soc_add_controls(codec, ak4671_snd_controls,
 			     ARRAY_SIZE(ak4671_snd_controls));
-	ak4671_add_widgets(codec);
 
 	ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
@@ -670,6 +658,10 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
 	.reg_cache_size = AK4671_CACHEREGNUM,
 	.reg_word_size = sizeof(u8),
 	.reg_cache_default = ak4671_reg,
+	.dapm_widgets = ak4671_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(ak4671_dapm_widgets),
+	.dapm_routes = ak4671_intercon,
+	.num_dapm_routes = ARRAY_SIZE(ak4671_intercon),
 };
 
 static int __devinit ak4671_i2c_probe(struct i2c_client *client,
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
index 0bb424af956f..d68ea532cc7f 100644
--- a/sound/soc/codecs/cx20442.c
+++ b/sound/soc/codecs/cx20442.c
@@ -86,18 +86,6 @@ static const struct snd_soc_dapm_route cx20442_audio_map[] = {
 	{"ADC", NULL, "Input Mixer"},
 };
 
-static int cx20442_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, cx20442_dapm_widgets,
-				  ARRAY_SIZE(cx20442_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, cx20442_audio_map,
-				ARRAY_SIZE(cx20442_audio_map));
-
-	return 0;
-}
-
 static unsigned int cx20442_read_reg_cache(struct snd_soc_codec *codec,
 							unsigned int reg)
 {
@@ -344,8 +332,6 @@ static int cx20442_codec_probe(struct snd_soc_codec *codec)
 		return -ENOMEM;
 	snd_soc_codec_set_drvdata(codec, cx20442);
 
-	cx20442_add_widgets(codec);
-
 	cx20442->control_data = NULL;
 	codec->hw_write = NULL;
 	codec->card->pop_time = 0;
@@ -377,6 +363,10 @@ static struct snd_soc_codec_driver cx20442_codec_dev = {
 	.reg_word_size = sizeof(u8),
 	.read = cx20442_read_reg_cache,
 	.write = cx20442_write,
+	.dapm_widgets = cx20442_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(cx20442_dapm_widgets),
+	.dapm_routes = cx20442_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(cx20442_audio_map),
 };
 
 static int cx20442_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c
index 57e9dac88d38..f9a87737ec16 100644
--- a/sound/soc/codecs/dmic.c
+++ b/sound/soc/codecs/dmic.c
@@ -39,7 +39,31 @@ static struct snd_soc_dai_driver dmic_dai = {
 	},
 };
 
-static struct snd_soc_codec_driver soc_dmic = {};
+static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_OUT("DMIC AIF", "Capture", 0,
+			     SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_INPUT("DMic"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+	{"DMIC AIF", NULL, "DMic"},
+};
+
+static int dmic_probe(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	snd_soc_dapm_new_controls(dapm, dmic_dapm_widgets,
+				  ARRAY_SIZE(dmic_dapm_widgets));
+        snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
+	snd_soc_dapm_new_widgets(dapm);
+
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_dmic = {
+	.probe	= dmic_probe,
+};
 
 static int __devinit dmic_dev_probe(struct platform_device *pdev)
 {
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
index f5ccdbf7ebc6..e373f8f06907 100644
--- a/sound/soc/codecs/jz4740.c
+++ b/sound/soc/codecs/jz4740.c
@@ -294,20 +294,9 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
 
 static int jz4740_codec_dev_probe(struct snd_soc_codec *codec)
 {
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
 	snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
 			JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
 
-	snd_soc_add_controls(codec, jz4740_codec_controls,
-		ARRAY_SIZE(jz4740_codec_controls));
-
-	snd_soc_dapm_new_controls(dapm, jz4740_codec_dapm_widgets,
-		ARRAY_SIZE(jz4740_codec_dapm_widgets));
-
-	snd_soc_dapm_add_routes(dapm, jz4740_codec_dapm_routes,
-		ARRAY_SIZE(jz4740_codec_dapm_routes));
-
 	jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
 	return 0;
@@ -348,6 +337,13 @@ static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = {
 	.reg_cache_default	= jz4740_codec_regs,
 	.reg_word_size = sizeof(u32),
 	.reg_cache_size	= 2,
+
+	.controls = jz4740_codec_controls,
+	.num_controls = ARRAY_SIZE(jz4740_codec_controls),
+	.dapm_widgets = jz4740_codec_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(jz4740_codec_dapm_widgets),
+	.dapm_routes = jz4740_codec_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(jz4740_codec_dapm_routes),
 };
 
 static int __devinit jz4740_codec_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index bd0517cb7980..4173b67c94d1 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -656,8 +656,6 @@ static const struct soc_enum max98088_exmode_enum =
                              ARRAY_SIZE(max98088_exmode_texts),
                              max98088_exmode_texts,
                              max98088_exmode_values);
-static const struct snd_kcontrol_new max98088_exmode_controls =
-       SOC_DAPM_VALUE_ENUM("Route", max98088_exmode_enum);
 
 static const char *max98088_ex_thresh[] = { /* volts PP */
        "0.6", "1.2", "1.8", "2.4", "3.0", "3.6", "4.2", "4.8"};
@@ -783,6 +781,7 @@ static const struct snd_kcontrol_new max98088_snd_controls[] = {
        SOC_SINGLE("EQ1 Switch", M98088_REG_49_CFG_LEVEL, 0, 1, 0),
        SOC_SINGLE("EQ2 Switch", M98088_REG_49_CFG_LEVEL, 1, 1, 0),
 
+       SOC_ENUM("EX Limiter Mode", max98088_exmode_enum),
        SOC_ENUM("EX Limiter Threshold", max98088_ex_thresh_enum),
 
        SOC_ENUM("DAI1 Filter Mode", max98088_filter_mode_enum),
@@ -808,10 +807,10 @@ static const struct snd_kcontrol_new max98088_snd_controls[] = {
 
 /* Left speaker mixer switch */
 static const struct snd_kcontrol_new max98088_left_speaker_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
-       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
-       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
-       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
        SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 5, 1, 0),
        SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 6, 1, 0),
        SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 1, 1, 0),
@@ -836,10 +835,10 @@ static const struct snd_kcontrol_new max98088_right_speaker_mixer_controls[] = {
 
 /* Left headphone mixer switch */
 static const struct snd_kcontrol_new max98088_left_hp_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
-       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
-       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
-       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
        SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_25_MIX_HP_LEFT, 5, 1, 0),
        SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_25_MIX_HP_LEFT, 6, 1, 0),
        SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_25_MIX_HP_LEFT, 1, 1, 0),
@@ -864,10 +863,10 @@ static const struct snd_kcontrol_new max98088_right_hp_mixer_controls[] = {
 
 /* Left earpiece/receiver mixer switch */
 static const struct snd_kcontrol_new max98088_left_rec_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
-       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
-       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
-       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
        SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_28_MIX_REC_LEFT, 5, 1, 0),
        SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_28_MIX_REC_LEFT, 6, 1, 0),
        SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_28_MIX_REC_LEFT, 1, 1, 0),
@@ -1094,9 +1093,6 @@ static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = {
 
        SND_SOC_DAPM_MICBIAS("MICBIAS", M98088_REG_4C_PWR_EN_IN, 3, 0),
 
-       SND_SOC_DAPM_MUX("EX Limiter Mode", SND_SOC_NOPM, 0, 0,
-               &max98088_exmode_controls),
-
        SND_SOC_DAPM_OUTPUT("HPL"),
        SND_SOC_DAPM_OUTPUT("HPR"),
        SND_SOC_DAPM_OUTPUT("SPKL"),
@@ -1112,7 +1108,7 @@ static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("INB2"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route max98088_audio_map[] = {
        /* Left headphone output mixer */
        {"Left HP Mixer", "Left DAC1 Switch", "DACL1"},
        {"Left HP Mixer", "Left DAC2 Switch", "DACL2"},
@@ -1226,22 +1222,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"MIC2 Input", NULL, "MIC2"},
 };
 
-static int max98088_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, max98088_dapm_widgets,
-                                 ARRAY_SIZE(max98088_dapm_widgets));
-
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       snd_soc_add_controls(codec, max98088_snd_controls,
-                            ARRAY_SIZE(max98088_snd_controls));
-
-       snd_soc_dapm_new_widgets(dapm);
-       return 0;
-}
-
 /* codec mclk clock divider coefficients */
 static const struct {
        u32 rate;
@@ -1586,6 +1566,36 @@ static int max98088_dai2_set_fmt(struct snd_soc_dai *codec_dai,
        return 0;
 }
 
+static int max98088_dai1_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int reg;
+
+       if (mute)
+               reg = M98088_DAI_MUTE;
+       else
+               reg = 0;
+
+       snd_soc_update_bits(codec, M98088_REG_2F_LVL_DAI1_PLAY,
+                           M98088_DAI_MUTE_MASK, reg);
+       return 0;
+}
+
+static int max98088_dai2_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int reg;
+
+       if (mute)
+               reg = M98088_DAI_MUTE;
+       else
+               reg = 0;
+
+       snd_soc_update_bits(codec, M98088_REG_31_LVL_DAI2_PLAY,
+                           M98088_DAI_MUTE_MASK, reg);
+       return 0;
+}
+
 static void max98088_sync_cache(struct snd_soc_codec *codec)
 {
        u16 *reg_cache = codec->reg_cache;
@@ -1647,12 +1657,14 @@ static struct snd_soc_dai_ops max98088_dai1_ops = {
        .set_sysclk = max98088_dai_set_sysclk,
        .set_fmt = max98088_dai1_set_fmt,
        .hw_params = max98088_dai1_hw_params,
+       .digital_mute = max98088_dai1_digital_mute,
 };
 
 static struct snd_soc_dai_ops max98088_dai2_ops = {
        .set_sysclk = max98088_dai_set_sysclk,
        .set_fmt = max98088_dai2_set_fmt,
        .hw_params = max98088_dai2_hw_params,
+       .digital_mute = max98088_dai2_digital_mute,
 };
 
 static struct snd_soc_dai_driver max98088_dai[] = {
@@ -2010,7 +2022,8 @@ static int max98088_probe(struct snd_soc_codec *codec)
 
        max98088_handle_pdata(codec);
 
-       max98088_add_widgets(codec);
+       snd_soc_add_controls(codec, max98088_snd_controls,
+                            ARRAY_SIZE(max98088_snd_controls));
 
 err_access:
        return ret;
@@ -2036,6 +2049,10 @@ static struct snd_soc_codec_driver soc_codec_dev_max98088 = {
        .reg_word_size = sizeof(u8),
        .reg_cache_default = max98088_reg,
        .volatile_register = max98088_volatile_register,
+	.dapm_widgets = max98088_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(max98088_dapm_widgets),
+	.dapm_routes = max98088_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(max98088_audio_map),
 };
 
 static int max98088_i2c_probe(struct i2c_client *i2c,
diff --git a/sound/soc/codecs/max98088.h b/sound/soc/codecs/max98088.h
index 56554c797fef..be89a4f4aab8 100644
--- a/sound/soc/codecs/max98088.h
+++ b/sound/soc/codecs/max98088.h
@@ -133,6 +133,19 @@
        #define M98088_REC_LINEMODE             (1<<7)
        #define M98088_REC_LINEMODE_MASK        (1<<7)
 
+/* M98088_REG_2D_MIX_SPK_CNTL */
+       #define M98088_MIX_SPKR_GAIN_MASK       (3<<2)
+       #define M98088_MIX_SPKR_GAIN_SHIFT      2
+       #define M98088_MIX_SPKL_GAIN_MASK       (3<<0)
+       #define M98088_MIX_SPKL_GAIN_SHIFT      0
+
+/* M98088_REG_2F_LVL_DAI1_PLAY, M98088_REG_31_LVL_DAI2_PLAY */
+       #define M98088_DAI_MUTE                 (1<<7)
+       #define M98088_DAI_MUTE_MASK            (1<<7)
+       #define M98088_DAI_VOICE_GAIN_MASK      (3<<4)
+       #define M98088_DAI_ATTENUATION_MASK     (0xF<<0)
+       #define M98088_DAI_ATTENUATION_SHIFT    0
+
 /* M98088_REG_35_LVL_MIC1, M98088_REG_36_LVL_MIC2 */
        #define M98088_MICPRE_MASK              (3<<5)
        #define M98088_MICPRE_SHIFT             5
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
new file mode 100644
index 000000000000..e1d282d477da
--- /dev/null
+++ b/sound/soc/codecs/max98095.c
@@ -0,0 +1,2396 @@
+/*
+ * max98095.c -- MAX98095 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Maxim Integrated Products
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.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/initval.h>
+#include <sound/tlv.h>
+#include <linux/slab.h>
+#include <asm/div64.h>
+#include <sound/max98095.h>
+#include "max98095.h"
+
+enum max98095_type {
+	MAX98095,
+};
+
+struct max98095_cdata {
+	unsigned int rate;
+	unsigned int fmt;
+	int eq_sel;
+	int bq_sel;
+};
+
+struct max98095_priv {
+	enum max98095_type devtype;
+	void *control_data;
+	struct max98095_pdata *pdata;
+	unsigned int sysclk;
+	struct max98095_cdata dai[3];
+	const char **eq_texts;
+	const char **bq_texts;
+	struct soc_enum eq_enum;
+	struct soc_enum bq_enum;
+	int eq_textcnt;
+	int bq_textcnt;
+	u8 lin_state;
+	unsigned int mic1pre;
+	unsigned int mic2pre;
+};
+
+static const u8 max98095_reg_def[M98095_REG_CNT] = {
+	0x00, /* 00 */
+	0x00, /* 01 */
+	0x00, /* 02 */
+	0x00, /* 03 */
+	0x00, /* 04 */
+	0x00, /* 05 */
+	0x00, /* 06 */
+	0x00, /* 07 */
+	0x00, /* 08 */
+	0x00, /* 09 */
+	0x00, /* 0A */
+	0x00, /* 0B */
+	0x00, /* 0C */
+	0x00, /* 0D */
+	0x00, /* 0E */
+	0x00, /* 0F */
+	0x00, /* 10 */
+	0x00, /* 11 */
+	0x00, /* 12 */
+	0x00, /* 13 */
+	0x00, /* 14 */
+	0x00, /* 15 */
+	0x00, /* 16 */
+	0x00, /* 17 */
+	0x00, /* 18 */
+	0x00, /* 19 */
+	0x00, /* 1A */
+	0x00, /* 1B */
+	0x00, /* 1C */
+	0x00, /* 1D */
+	0x00, /* 1E */
+	0x00, /* 1F */
+	0x00, /* 20 */
+	0x00, /* 21 */
+	0x00, /* 22 */
+	0x00, /* 23 */
+	0x00, /* 24 */
+	0x00, /* 25 */
+	0x00, /* 26 */
+	0x00, /* 27 */
+	0x00, /* 28 */
+	0x00, /* 29 */
+	0x00, /* 2A */
+	0x00, /* 2B */
+	0x00, /* 2C */
+	0x00, /* 2D */
+	0x00, /* 2E */
+	0x00, /* 2F */
+	0x00, /* 30 */
+	0x00, /* 31 */
+	0x00, /* 32 */
+	0x00, /* 33 */
+	0x00, /* 34 */
+	0x00, /* 35 */
+	0x00, /* 36 */
+	0x00, /* 37 */
+	0x00, /* 38 */
+	0x00, /* 39 */
+	0x00, /* 3A */
+	0x00, /* 3B */
+	0x00, /* 3C */
+	0x00, /* 3D */
+	0x00, /* 3E */
+	0x00, /* 3F */
+	0x00, /* 40 */
+	0x00, /* 41 */
+	0x00, /* 42 */
+	0x00, /* 43 */
+	0x00, /* 44 */
+	0x00, /* 45 */
+	0x00, /* 46 */
+	0x00, /* 47 */
+	0x00, /* 48 */
+	0x00, /* 49 */
+	0x00, /* 4A */
+	0x00, /* 4B */
+	0x00, /* 4C */
+	0x00, /* 4D */
+	0x00, /* 4E */
+	0x00, /* 4F */
+	0x00, /* 50 */
+	0x00, /* 51 */
+	0x00, /* 52 */
+	0x00, /* 53 */
+	0x00, /* 54 */
+	0x00, /* 55 */
+	0x00, /* 56 */
+	0x00, /* 57 */
+	0x00, /* 58 */
+	0x00, /* 59 */
+	0x00, /* 5A */
+	0x00, /* 5B */
+	0x00, /* 5C */
+	0x00, /* 5D */
+	0x00, /* 5E */
+	0x00, /* 5F */
+	0x00, /* 60 */
+	0x00, /* 61 */
+	0x00, /* 62 */
+	0x00, /* 63 */
+	0x00, /* 64 */
+	0x00, /* 65 */
+	0x00, /* 66 */
+	0x00, /* 67 */
+	0x00, /* 68 */
+	0x00, /* 69 */
+	0x00, /* 6A */
+	0x00, /* 6B */
+	0x00, /* 6C */
+	0x00, /* 6D */
+	0x00, /* 6E */
+	0x00, /* 6F */
+	0x00, /* 70 */
+	0x00, /* 71 */
+	0x00, /* 72 */
+	0x00, /* 73 */
+	0x00, /* 74 */
+	0x00, /* 75 */
+	0x00, /* 76 */
+	0x00, /* 77 */
+	0x00, /* 78 */
+	0x00, /* 79 */
+	0x00, /* 7A */
+	0x00, /* 7B */
+	0x00, /* 7C */
+	0x00, /* 7D */
+	0x00, /* 7E */
+	0x00, /* 7F */
+	0x00, /* 80 */
+	0x00, /* 81 */
+	0x00, /* 82 */
+	0x00, /* 83 */
+	0x00, /* 84 */
+	0x00, /* 85 */
+	0x00, /* 86 */
+	0x00, /* 87 */
+	0x00, /* 88 */
+	0x00, /* 89 */
+	0x00, /* 8A */
+	0x00, /* 8B */
+	0x00, /* 8C */
+	0x00, /* 8D */
+	0x00, /* 8E */
+	0x00, /* 8F */
+	0x00, /* 90 */
+	0x00, /* 91 */
+	0x30, /* 92 */
+	0xF0, /* 93 */
+	0x00, /* 94 */
+	0x00, /* 95 */
+	0x3F, /* 96 */
+	0x00, /* 97 */
+	0x00, /* 98 */
+	0x00, /* 99 */
+	0x00, /* 9A */
+	0x00, /* 9B */
+	0x00, /* 9C */
+	0x00, /* 9D */
+	0x00, /* 9E */
+	0x00, /* 9F */
+	0x00, /* A0 */
+	0x00, /* A1 */
+	0x00, /* A2 */
+	0x00, /* A3 */
+	0x00, /* A4 */
+	0x00, /* A5 */
+	0x00, /* A6 */
+	0x00, /* A7 */
+	0x00, /* A8 */
+	0x00, /* A9 */
+	0x00, /* AA */
+	0x00, /* AB */
+	0x00, /* AC */
+	0x00, /* AD */
+	0x00, /* AE */
+	0x00, /* AF */
+	0x00, /* B0 */
+	0x00, /* B1 */
+	0x00, /* B2 */
+	0x00, /* B3 */
+	0x00, /* B4 */
+	0x00, /* B5 */
+	0x00, /* B6 */
+	0x00, /* B7 */
+	0x00, /* B8 */
+	0x00, /* B9 */
+	0x00, /* BA */
+	0x00, /* BB */
+	0x00, /* BC */
+	0x00, /* BD */
+	0x00, /* BE */
+	0x00, /* BF */
+	0x00, /* C0 */
+	0x00, /* C1 */
+	0x00, /* C2 */
+	0x00, /* C3 */
+	0x00, /* C4 */
+	0x00, /* C5 */
+	0x00, /* C6 */
+	0x00, /* C7 */
+	0x00, /* C8 */
+	0x00, /* C9 */
+	0x00, /* CA */
+	0x00, /* CB */
+	0x00, /* CC */
+	0x00, /* CD */
+	0x00, /* CE */
+	0x00, /* CF */
+	0x00, /* D0 */
+	0x00, /* D1 */
+	0x00, /* D2 */
+	0x00, /* D3 */
+	0x00, /* D4 */
+	0x00, /* D5 */
+	0x00, /* D6 */
+	0x00, /* D7 */
+	0x00, /* D8 */
+	0x00, /* D9 */
+	0x00, /* DA */
+	0x00, /* DB */
+	0x00, /* DC */
+	0x00, /* DD */
+	0x00, /* DE */
+	0x00, /* DF */
+	0x00, /* E0 */
+	0x00, /* E1 */
+	0x00, /* E2 */
+	0x00, /* E3 */
+	0x00, /* E4 */
+	0x00, /* E5 */
+	0x00, /* E6 */
+	0x00, /* E7 */
+	0x00, /* E8 */
+	0x00, /* E9 */
+	0x00, /* EA */
+	0x00, /* EB */
+	0x00, /* EC */
+	0x00, /* ED */
+	0x00, /* EE */
+	0x00, /* EF */
+	0x00, /* F0 */
+	0x00, /* F1 */
+	0x00, /* F2 */
+	0x00, /* F3 */
+	0x00, /* F4 */
+	0x00, /* F5 */
+	0x00, /* F6 */
+	0x00, /* F7 */
+	0x00, /* F8 */
+	0x00, /* F9 */
+	0x00, /* FA */
+	0x00, /* FB */
+	0x00, /* FC */
+	0x00, /* FD */
+	0x00, /* FE */
+	0x00, /* FF */
+};
+
+static struct {
+	int readable;
+	int writable;
+} max98095_access[M98095_REG_CNT] = {
+	{ 0x00, 0x00 }, /* 00 */
+	{ 0xFF, 0x00 }, /* 01 */
+	{ 0xFF, 0x00 }, /* 02 */
+	{ 0xFF, 0x00 }, /* 03 */
+	{ 0xFF, 0x00 }, /* 04 */
+	{ 0xFF, 0x00 }, /* 05 */
+	{ 0xFF, 0x00 }, /* 06 */
+	{ 0xFF, 0x00 }, /* 07 */
+	{ 0xFF, 0x00 }, /* 08 */
+	{ 0xFF, 0x00 }, /* 09 */
+	{ 0xFF, 0x00 }, /* 0A */
+	{ 0xFF, 0x00 }, /* 0B */
+	{ 0xFF, 0x00 }, /* 0C */
+	{ 0xFF, 0x00 }, /* 0D */
+	{ 0xFF, 0x00 }, /* 0E */
+	{ 0xFF, 0x9F }, /* 0F */
+	{ 0xFF, 0xFF }, /* 10 */
+	{ 0xFF, 0xFF }, /* 11 */
+	{ 0xFF, 0xFF }, /* 12 */
+	{ 0xFF, 0xFF }, /* 13 */
+	{ 0xFF, 0xFF }, /* 14 */
+	{ 0xFF, 0xFF }, /* 15 */
+	{ 0xFF, 0xFF }, /* 16 */
+	{ 0xFF, 0xFF }, /* 17 */
+	{ 0xFF, 0xFF }, /* 18 */
+	{ 0xFF, 0xFF }, /* 19 */
+	{ 0xFF, 0xFF }, /* 1A */
+	{ 0xFF, 0xFF }, /* 1B */
+	{ 0xFF, 0xFF }, /* 1C */
+	{ 0xFF, 0xFF }, /* 1D */
+	{ 0xFF, 0x77 }, /* 1E */
+	{ 0xFF, 0x77 }, /* 1F */
+	{ 0xFF, 0x77 }, /* 20 */
+	{ 0xFF, 0x77 }, /* 21 */
+	{ 0xFF, 0x77 }, /* 22 */
+	{ 0xFF, 0x77 }, /* 23 */
+	{ 0xFF, 0xFF }, /* 24 */
+	{ 0xFF, 0x7F }, /* 25 */
+	{ 0xFF, 0x31 }, /* 26 */
+	{ 0xFF, 0xFF }, /* 27 */
+	{ 0xFF, 0xFF }, /* 28 */
+	{ 0xFF, 0xFF }, /* 29 */
+	{ 0xFF, 0xF7 }, /* 2A */
+	{ 0xFF, 0x2F }, /* 2B */
+	{ 0xFF, 0xEF }, /* 2C */
+	{ 0xFF, 0xFF }, /* 2D */
+	{ 0xFF, 0xFF }, /* 2E */
+	{ 0xFF, 0xFF }, /* 2F */
+	{ 0xFF, 0xFF }, /* 30 */
+	{ 0xFF, 0xFF }, /* 31 */
+	{ 0xFF, 0xFF }, /* 32 */
+	{ 0xFF, 0xFF }, /* 33 */
+	{ 0xFF, 0xF7 }, /* 34 */
+	{ 0xFF, 0x2F }, /* 35 */
+	{ 0xFF, 0xCF }, /* 36 */
+	{ 0xFF, 0xFF }, /* 37 */
+	{ 0xFF, 0xFF }, /* 38 */
+	{ 0xFF, 0xFF }, /* 39 */
+	{ 0xFF, 0xFF }, /* 3A */
+	{ 0xFF, 0xFF }, /* 3B */
+	{ 0xFF, 0xFF }, /* 3C */
+	{ 0xFF, 0xFF }, /* 3D */
+	{ 0xFF, 0xF7 }, /* 3E */
+	{ 0xFF, 0x2F }, /* 3F */
+	{ 0xFF, 0xCF }, /* 40 */
+	{ 0xFF, 0xFF }, /* 41 */
+	{ 0xFF, 0x77 }, /* 42 */
+	{ 0xFF, 0xFF }, /* 43 */
+	{ 0xFF, 0xFF }, /* 44 */
+	{ 0xFF, 0xFF }, /* 45 */
+	{ 0xFF, 0xFF }, /* 46 */
+	{ 0xFF, 0xFF }, /* 47 */
+	{ 0xFF, 0xFF }, /* 48 */
+	{ 0xFF, 0x0F }, /* 49 */
+	{ 0xFF, 0xFF }, /* 4A */
+	{ 0xFF, 0xFF }, /* 4B */
+	{ 0xFF, 0x3F }, /* 4C */
+	{ 0xFF, 0x3F }, /* 4D */
+	{ 0xFF, 0x3F }, /* 4E */
+	{ 0xFF, 0xFF }, /* 4F */
+	{ 0xFF, 0x7F }, /* 50 */
+	{ 0xFF, 0x7F }, /* 51 */
+	{ 0xFF, 0x0F }, /* 52 */
+	{ 0xFF, 0x3F }, /* 53 */
+	{ 0xFF, 0x3F }, /* 54 */
+	{ 0xFF, 0x3F }, /* 55 */
+	{ 0xFF, 0xFF }, /* 56 */
+	{ 0xFF, 0xFF }, /* 57 */
+	{ 0xFF, 0xBF }, /* 58 */
+	{ 0xFF, 0x1F }, /* 59 */
+	{ 0xFF, 0xBF }, /* 5A */
+	{ 0xFF, 0x1F }, /* 5B */
+	{ 0xFF, 0xBF }, /* 5C */
+	{ 0xFF, 0x3F }, /* 5D */
+	{ 0xFF, 0x3F }, /* 5E */
+	{ 0xFF, 0x7F }, /* 5F */
+	{ 0xFF, 0x7F }, /* 60 */
+	{ 0xFF, 0x47 }, /* 61 */
+	{ 0xFF, 0x9F }, /* 62 */
+	{ 0xFF, 0x9F }, /* 63 */
+	{ 0xFF, 0x9F }, /* 64 */
+	{ 0xFF, 0x9F }, /* 65 */
+	{ 0xFF, 0x9F }, /* 66 */
+	{ 0xFF, 0xBF }, /* 67 */
+	{ 0xFF, 0xBF }, /* 68 */
+	{ 0xFF, 0xFF }, /* 69 */
+	{ 0xFF, 0xFF }, /* 6A */
+	{ 0xFF, 0x7F }, /* 6B */
+	{ 0xFF, 0xF7 }, /* 6C */
+	{ 0xFF, 0xFF }, /* 6D */
+	{ 0xFF, 0xFF }, /* 6E */
+	{ 0xFF, 0x1F }, /* 6F */
+	{ 0xFF, 0xF7 }, /* 70 */
+	{ 0xFF, 0xFF }, /* 71 */
+	{ 0xFF, 0xFF }, /* 72 */
+	{ 0xFF, 0x1F }, /* 73 */
+	{ 0xFF, 0xF7 }, /* 74 */
+	{ 0xFF, 0xFF }, /* 75 */
+	{ 0xFF, 0xFF }, /* 76 */
+	{ 0xFF, 0x1F }, /* 77 */
+	{ 0xFF, 0xF7 }, /* 78 */
+	{ 0xFF, 0xFF }, /* 79 */
+	{ 0xFF, 0xFF }, /* 7A */
+	{ 0xFF, 0x1F }, /* 7B */
+	{ 0xFF, 0xF7 }, /* 7C */
+	{ 0xFF, 0xFF }, /* 7D */
+	{ 0xFF, 0xFF }, /* 7E */
+	{ 0xFF, 0x1F }, /* 7F */
+	{ 0xFF, 0xF7 }, /* 80 */
+	{ 0xFF, 0xFF }, /* 81 */
+	{ 0xFF, 0xFF }, /* 82 */
+	{ 0xFF, 0x1F }, /* 83 */
+	{ 0xFF, 0x7F }, /* 84 */
+	{ 0xFF, 0x0F }, /* 85 */
+	{ 0xFF, 0xD8 }, /* 86 */
+	{ 0xFF, 0xFF }, /* 87 */
+	{ 0xFF, 0xEF }, /* 88 */
+	{ 0xFF, 0xFE }, /* 89 */
+	{ 0xFF, 0xFE }, /* 8A */
+	{ 0xFF, 0xFF }, /* 8B */
+	{ 0xFF, 0xFF }, /* 8C */
+	{ 0xFF, 0x3F }, /* 8D */
+	{ 0xFF, 0xFF }, /* 8E */
+	{ 0xFF, 0x3F }, /* 8F */
+	{ 0xFF, 0x8F }, /* 90 */
+	{ 0xFF, 0xFF }, /* 91 */
+	{ 0xFF, 0x3F }, /* 92 */
+	{ 0xFF, 0xFF }, /* 93 */
+	{ 0xFF, 0xFF }, /* 94 */
+	{ 0xFF, 0x0F }, /* 95 */
+	{ 0xFF, 0x3F }, /* 96 */
+	{ 0xFF, 0x8C }, /* 97 */
+	{ 0x00, 0x00 }, /* 98 */
+	{ 0x00, 0x00 }, /* 99 */
+	{ 0x00, 0x00 }, /* 9A */
+	{ 0x00, 0x00 }, /* 9B */
+	{ 0x00, 0x00 }, /* 9C */
+	{ 0x00, 0x00 }, /* 9D */
+	{ 0x00, 0x00 }, /* 9E */
+	{ 0x00, 0x00 }, /* 9F */
+	{ 0x00, 0x00 }, /* A0 */
+	{ 0x00, 0x00 }, /* A1 */
+	{ 0x00, 0x00 }, /* A2 */
+	{ 0x00, 0x00 }, /* A3 */
+	{ 0x00, 0x00 }, /* A4 */
+	{ 0x00, 0x00 }, /* A5 */
+	{ 0x00, 0x00 }, /* A6 */
+	{ 0x00, 0x00 }, /* A7 */
+	{ 0x00, 0x00 }, /* A8 */
+	{ 0x00, 0x00 }, /* A9 */
+	{ 0x00, 0x00 }, /* AA */
+	{ 0x00, 0x00 }, /* AB */
+	{ 0x00, 0x00 }, /* AC */
+	{ 0x00, 0x00 }, /* AD */
+	{ 0x00, 0x00 }, /* AE */
+	{ 0x00, 0x00 }, /* AF */
+	{ 0x00, 0x00 }, /* B0 */
+	{ 0x00, 0x00 }, /* B1 */
+	{ 0x00, 0x00 }, /* B2 */
+	{ 0x00, 0x00 }, /* B3 */
+	{ 0x00, 0x00 }, /* B4 */
+	{ 0x00, 0x00 }, /* B5 */
+	{ 0x00, 0x00 }, /* B6 */
+	{ 0x00, 0x00 }, /* B7 */
+	{ 0x00, 0x00 }, /* B8 */
+	{ 0x00, 0x00 }, /* B9 */
+	{ 0x00, 0x00 }, /* BA */
+	{ 0x00, 0x00 }, /* BB */
+	{ 0x00, 0x00 }, /* BC */
+	{ 0x00, 0x00 }, /* BD */
+	{ 0x00, 0x00 }, /* BE */
+	{ 0x00, 0x00 }, /* BF */
+	{ 0x00, 0x00 }, /* C0 */
+	{ 0x00, 0x00 }, /* C1 */
+	{ 0x00, 0x00 }, /* C2 */
+	{ 0x00, 0x00 }, /* C3 */
+	{ 0x00, 0x00 }, /* C4 */
+	{ 0x00, 0x00 }, /* C5 */
+	{ 0x00, 0x00 }, /* C6 */
+	{ 0x00, 0x00 }, /* C7 */
+	{ 0x00, 0x00 }, /* C8 */
+	{ 0x00, 0x00 }, /* C9 */
+	{ 0x00, 0x00 }, /* CA */
+	{ 0x00, 0x00 }, /* CB */
+	{ 0x00, 0x00 }, /* CC */
+	{ 0x00, 0x00 }, /* CD */
+	{ 0x00, 0x00 }, /* CE */
+	{ 0x00, 0x00 }, /* CF */
+	{ 0x00, 0x00 }, /* D0 */
+	{ 0x00, 0x00 }, /* D1 */
+	{ 0x00, 0x00 }, /* D2 */
+	{ 0x00, 0x00 }, /* D3 */
+	{ 0x00, 0x00 }, /* D4 */
+	{ 0x00, 0x00 }, /* D5 */
+	{ 0x00, 0x00 }, /* D6 */
+	{ 0x00, 0x00 }, /* D7 */
+	{ 0x00, 0x00 }, /* D8 */
+	{ 0x00, 0x00 }, /* D9 */
+	{ 0x00, 0x00 }, /* DA */
+	{ 0x00, 0x00 }, /* DB */
+	{ 0x00, 0x00 }, /* DC */
+	{ 0x00, 0x00 }, /* DD */
+	{ 0x00, 0x00 }, /* DE */
+	{ 0x00, 0x00 }, /* DF */
+	{ 0x00, 0x00 }, /* E0 */
+	{ 0x00, 0x00 }, /* E1 */
+	{ 0x00, 0x00 }, /* E2 */
+	{ 0x00, 0x00 }, /* E3 */
+	{ 0x00, 0x00 }, /* E4 */
+	{ 0x00, 0x00 }, /* E5 */
+	{ 0x00, 0x00 }, /* E6 */
+	{ 0x00, 0x00 }, /* E7 */
+	{ 0x00, 0x00 }, /* E8 */
+	{ 0x00, 0x00 }, /* E9 */
+	{ 0x00, 0x00 }, /* EA */
+	{ 0x00, 0x00 }, /* EB */
+	{ 0x00, 0x00 }, /* EC */
+	{ 0x00, 0x00 }, /* ED */
+	{ 0x00, 0x00 }, /* EE */
+	{ 0x00, 0x00 }, /* EF */
+	{ 0x00, 0x00 }, /* F0 */
+	{ 0x00, 0x00 }, /* F1 */
+	{ 0x00, 0x00 }, /* F2 */
+	{ 0x00, 0x00 }, /* F3 */
+	{ 0x00, 0x00 }, /* F4 */
+	{ 0x00, 0x00 }, /* F5 */
+	{ 0x00, 0x00 }, /* F6 */
+	{ 0x00, 0x00 }, /* F7 */
+	{ 0x00, 0x00 }, /* F8 */
+	{ 0x00, 0x00 }, /* F9 */
+	{ 0x00, 0x00 }, /* FA */
+	{ 0x00, 0x00 }, /* FB */
+	{ 0x00, 0x00 }, /* FC */
+	{ 0x00, 0x00 }, /* FD */
+	{ 0x00, 0x00 }, /* FE */
+	{ 0xFF, 0x00 }, /* FF */
+};
+
+static int max98095_readable(struct snd_soc_codec *codec, unsigned int reg)
+{
+	if (reg >= M98095_REG_CNT)
+		return 0;
+	return max98095_access[reg].readable != 0;
+}
+
+static int max98095_volatile(struct snd_soc_codec *codec, unsigned int reg)
+{
+	if (reg > M98095_REG_MAX_CACHED)
+		return 1;
+
+	switch (reg) {
+	case M98095_000_HOST_DATA:
+	case M98095_001_HOST_INT_STS:
+	case M98095_002_HOST_RSP_STS:
+	case M98095_003_HOST_CMD_STS:
+	case M98095_004_CODEC_STS:
+	case M98095_005_DAI1_ALC_STS:
+	case M98095_006_DAI2_ALC_STS:
+	case M98095_007_JACK_AUTO_STS:
+	case M98095_008_JACK_MANUAL_STS:
+	case M98095_009_JACK_VBAT_STS:
+	case M98095_00A_ACC_ADC_STS:
+	case M98095_00B_MIC_NG_AGC_STS:
+	case M98095_00C_SPK_L_VOLT_STS:
+	case M98095_00D_SPK_R_VOLT_STS:
+	case M98095_00E_TEMP_SENSOR_STS:
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Filter coefficients are in a separate register segment
+ * and they share the address space of the normal registers.
+ * The coefficient registers do not need or share the cache.
+ */
+static int max98095_hw_write(struct snd_soc_codec *codec, unsigned int reg,
+			     unsigned int value)
+{
+	u8 data[2];
+
+	data[0] = reg;
+	data[1] = value;
+	if (codec->hw_write(codec->control_data, data, 2) == 2)
+		return 0;
+	else
+		return -EIO;
+}
+
+/*
+ * Load equalizer DSP coefficient configurations registers
+ */
+static void m98095_eq_band(struct snd_soc_codec *codec, unsigned int dai,
+		    unsigned int band, u16 *coefs)
+{
+	unsigned int eq_reg;
+	unsigned int i;
+
+	BUG_ON(band > 4);
+	BUG_ON(dai > 1);
+
+	/* Load the base register address */
+	eq_reg = dai ? M98095_142_DAI2_EQ_BASE : M98095_110_DAI1_EQ_BASE;
+
+	/* Add the band address offset, note adjustment for word address */
+	eq_reg += band * (M98095_COEFS_PER_BAND << 1);
+
+	/* Step through the registers and coefs */
+	for (i = 0; i < M98095_COEFS_PER_BAND; i++) {
+		max98095_hw_write(codec, eq_reg++, M98095_BYTE1(coefs[i]));
+		max98095_hw_write(codec, eq_reg++, M98095_BYTE0(coefs[i]));
+	}
+}
+
+/*
+ * Load biquad filter coefficient configurations registers
+ */
+static void m98095_biquad_band(struct snd_soc_codec *codec, unsigned int dai,
+		    unsigned int band, u16 *coefs)
+{
+	unsigned int bq_reg;
+	unsigned int i;
+
+	BUG_ON(band > 1);
+	BUG_ON(dai > 1);
+
+	/* Load the base register address */
+	bq_reg = dai ? M98095_17E_DAI2_BQ_BASE : M98095_174_DAI1_BQ_BASE;
+
+	/* Add the band address offset, note adjustment for word address */
+	bq_reg += band * (M98095_COEFS_PER_BAND << 1);
+
+	/* Step through the registers and coefs */
+	for (i = 0; i < M98095_COEFS_PER_BAND; i++) {
+		max98095_hw_write(codec, bq_reg++, M98095_BYTE1(coefs[i]));
+		max98095_hw_write(codec, bq_reg++, M98095_BYTE0(coefs[i]));
+	}
+}
+
+static const char * const max98095_fltr_mode[] = { "Voice", "Music" };
+static const struct soc_enum max98095_dai1_filter_mode_enum[] = {
+	SOC_ENUM_SINGLE(M98095_02E_DAI1_FILTERS, 7, 2, max98095_fltr_mode),
+};
+static const struct soc_enum max98095_dai2_filter_mode_enum[] = {
+	SOC_ENUM_SINGLE(M98095_038_DAI2_FILTERS, 7, 2, max98095_fltr_mode),
+};
+
+static const char * const max98095_extmic_text[] = { "None", "MIC1", "MIC2" };
+
+static const struct soc_enum max98095_extmic_enum =
+	SOC_ENUM_SINGLE(M98095_087_CFG_MIC, 0, 3, max98095_extmic_text);
+
+static const struct snd_kcontrol_new max98095_extmic_mux =
+	SOC_DAPM_ENUM("External MIC Mux", max98095_extmic_enum);
+
+static const char * const max98095_linein_text[] = { "INA", "INB" };
+
+static const struct soc_enum max98095_linein_enum =
+	SOC_ENUM_SINGLE(M98095_086_CFG_LINE, 6, 2, max98095_linein_text);
+
+static const struct snd_kcontrol_new max98095_linein_mux =
+	SOC_DAPM_ENUM("Linein Input Mux", max98095_linein_enum);
+
+static const char * const max98095_line_mode_text[] = {
+	"Stereo", "Differential"};
+
+static const struct soc_enum max98095_linein_mode_enum =
+	SOC_ENUM_SINGLE(M98095_086_CFG_LINE, 7, 2, max98095_line_mode_text);
+
+static const struct soc_enum max98095_lineout_mode_enum =
+	SOC_ENUM_SINGLE(M98095_086_CFG_LINE, 4, 2, max98095_line_mode_text);
+
+static const char * const max98095_dai_fltr[] = {
+	"Off", "Elliptical-HPF-16k", "Butterworth-HPF-16k",
+	"Elliptical-HPF-8k", "Butterworth-HPF-8k", "Butterworth-HPF-Fs/240"};
+static const struct soc_enum max98095_dai1_dac_filter_enum[] = {
+	SOC_ENUM_SINGLE(M98095_02E_DAI1_FILTERS, 0, 6, max98095_dai_fltr),
+};
+static const struct soc_enum max98095_dai2_dac_filter_enum[] = {
+	SOC_ENUM_SINGLE(M98095_038_DAI2_FILTERS, 0, 6, max98095_dai_fltr),
+};
+static const struct soc_enum max98095_dai3_dac_filter_enum[] = {
+	SOC_ENUM_SINGLE(M98095_042_DAI3_FILTERS, 0, 6, max98095_dai_fltr),
+};
+
+static int max98095_mic1pre_set(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	unsigned int sel = ucontrol->value.integer.value[0];
+
+	max98095->mic1pre = sel;
+	snd_soc_update_bits(codec, M98095_05F_LVL_MIC1, M98095_MICPRE_MASK,
+		(1+sel)<<M98095_MICPRE_SHIFT);
+
+	return 0;
+}
+
+static int max98095_mic1pre_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = max98095->mic1pre;
+	return 0;
+}
+
+static int max98095_mic2pre_set(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	unsigned int sel = ucontrol->value.integer.value[0];
+
+	max98095->mic2pre = sel;
+	snd_soc_update_bits(codec, M98095_060_LVL_MIC2, M98095_MICPRE_MASK,
+		(1+sel)<<M98095_MICPRE_SHIFT);
+
+	return 0;
+}
+
+static int max98095_mic2pre_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = max98095->mic2pre;
+	return 0;
+}
+
+static const unsigned int max98095_micboost_tlv[] = {
+	TLV_DB_RANGE_HEAD(2),
+	0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
+	2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
+};
+
+static const DECLARE_TLV_DB_SCALE(max98095_mic_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(max98095_adc_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(max98095_adcboost_tlv, 0, 600, 0);
+
+static const unsigned int max98095_hp_tlv[] = {
+	TLV_DB_RANGE_HEAD(5),
+	0, 6, TLV_DB_SCALE_ITEM(-6700, 400, 0),
+	7, 14, TLV_DB_SCALE_ITEM(-4000, 300, 0),
+	15, 21, TLV_DB_SCALE_ITEM(-1700, 200, 0),
+	22, 27, TLV_DB_SCALE_ITEM(-400, 100, 0),
+	28, 31, TLV_DB_SCALE_ITEM(150, 50, 0),
+};
+
+static const unsigned int max98095_spk_tlv[] = {
+	TLV_DB_RANGE_HEAD(4),
+	0, 10, TLV_DB_SCALE_ITEM(-5900, 400, 0),
+	11, 18, TLV_DB_SCALE_ITEM(-1700, 200, 0),
+	19, 27, TLV_DB_SCALE_ITEM(-200, 100, 0),
+	28, 39, TLV_DB_SCALE_ITEM(650, 50, 0),
+};
+
+static const unsigned int max98095_rcv_lout_tlv[] = {
+	TLV_DB_RANGE_HEAD(5),
+	0, 6, TLV_DB_SCALE_ITEM(-6200, 400, 0),
+	7, 14, TLV_DB_SCALE_ITEM(-3500, 300, 0),
+	15, 21, TLV_DB_SCALE_ITEM(-1200, 200, 0),
+	22, 27, TLV_DB_SCALE_ITEM(100, 100, 0),
+	28, 31, TLV_DB_SCALE_ITEM(650, 50, 0),
+};
+
+static const unsigned int max98095_lin_tlv[] = {
+	TLV_DB_RANGE_HEAD(3),
+	0, 2, TLV_DB_SCALE_ITEM(-600, 300, 0),
+	3, 3, TLV_DB_SCALE_ITEM(300, 1100, 0),
+	4, 5, TLV_DB_SCALE_ITEM(1400, 600, 0),
+};
+
+static const struct snd_kcontrol_new max98095_snd_controls[] = {
+
+	SOC_DOUBLE_R_TLV("Headphone Volume", M98095_064_LVL_HP_L,
+		M98095_065_LVL_HP_R, 0, 31, 0, max98095_hp_tlv),
+
+	SOC_DOUBLE_R_TLV("Speaker Volume", M98095_067_LVL_SPK_L,
+		M98095_068_LVL_SPK_R, 0, 39, 0, max98095_spk_tlv),
+
+	SOC_SINGLE_TLV("Receiver Volume", M98095_066_LVL_RCV,
+		0, 31, 0, max98095_rcv_lout_tlv),
+
+	SOC_DOUBLE_R_TLV("Lineout Volume", M98095_062_LVL_LINEOUT1,
+		M98095_063_LVL_LINEOUT2, 0, 31, 0, max98095_rcv_lout_tlv),
+
+	SOC_DOUBLE_R("Headphone Switch", M98095_064_LVL_HP_L,
+		M98095_065_LVL_HP_R, 7, 1, 1),
+
+	SOC_DOUBLE_R("Speaker Switch", M98095_067_LVL_SPK_L,
+		M98095_068_LVL_SPK_R, 7, 1, 1),
+
+	SOC_SINGLE("Receiver Switch", M98095_066_LVL_RCV, 7, 1, 1),
+
+	SOC_DOUBLE_R("Lineout Switch", M98095_062_LVL_LINEOUT1,
+		M98095_063_LVL_LINEOUT2, 7, 1, 1),
+
+	SOC_SINGLE_TLV("MIC1 Volume", M98095_05F_LVL_MIC1, 0, 20, 1,
+		max98095_mic_tlv),
+
+	SOC_SINGLE_TLV("MIC2 Volume", M98095_060_LVL_MIC2, 0, 20, 1,
+		max98095_mic_tlv),
+
+	SOC_SINGLE_EXT_TLV("MIC1 Boost Volume",
+			M98095_05F_LVL_MIC1, 5, 2, 0,
+			max98095_mic1pre_get, max98095_mic1pre_set,
+			max98095_micboost_tlv),
+	SOC_SINGLE_EXT_TLV("MIC2 Boost Volume",
+			M98095_060_LVL_MIC2, 5, 2, 0,
+			max98095_mic2pre_get, max98095_mic2pre_set,
+			max98095_micboost_tlv),
+
+	SOC_SINGLE_TLV("Linein Volume", M98095_061_LVL_LINEIN, 0, 5, 1,
+		max98095_lin_tlv),
+
+	SOC_SINGLE_TLV("ADCL Volume", M98095_05D_LVL_ADC_L, 0, 15, 1,
+		max98095_adc_tlv),
+	SOC_SINGLE_TLV("ADCR Volume", M98095_05E_LVL_ADC_R, 0, 15, 1,
+		max98095_adc_tlv),
+
+	SOC_SINGLE_TLV("ADCL Boost Volume", M98095_05D_LVL_ADC_L, 4, 3, 0,
+		max98095_adcboost_tlv),
+	SOC_SINGLE_TLV("ADCR Boost Volume", M98095_05E_LVL_ADC_R, 4, 3, 0,
+		max98095_adcboost_tlv),
+
+	SOC_SINGLE("EQ1 Switch", M98095_088_CFG_LEVEL, 0, 1, 0),
+	SOC_SINGLE("EQ2 Switch", M98095_088_CFG_LEVEL, 1, 1, 0),
+
+	SOC_SINGLE("Biquad1 Switch", M98095_088_CFG_LEVEL, 2, 1, 0),
+	SOC_SINGLE("Biquad2 Switch", M98095_088_CFG_LEVEL, 3, 1, 0),
+
+	SOC_ENUM("DAI1 Filter Mode", max98095_dai1_filter_mode_enum),
+	SOC_ENUM("DAI2 Filter Mode", max98095_dai2_filter_mode_enum),
+	SOC_ENUM("DAI1 DAC Filter", max98095_dai1_dac_filter_enum),
+	SOC_ENUM("DAI2 DAC Filter", max98095_dai2_dac_filter_enum),
+	SOC_ENUM("DAI3 DAC Filter", max98095_dai3_dac_filter_enum),
+
+	SOC_ENUM("Linein Mode", max98095_linein_mode_enum),
+	SOC_ENUM("Lineout Mode", max98095_lineout_mode_enum),
+};
+
+/* Left speaker mixer switch */
+static const struct snd_kcontrol_new max98095_left_speaker_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_050_MIX_SPK_LEFT, 0, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_050_MIX_SPK_LEFT, 6, 1, 0),
+	SOC_DAPM_SINGLE("Mono DAC2 Switch", M98095_050_MIX_SPK_LEFT, 3, 1, 0),
+	SOC_DAPM_SINGLE("Mono DAC3 Switch", M98095_050_MIX_SPK_LEFT, 3, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_050_MIX_SPK_LEFT, 4, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_050_MIX_SPK_LEFT, 5, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_050_MIX_SPK_LEFT, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_050_MIX_SPK_LEFT, 2, 1, 0),
+};
+
+/* Right speaker mixer switch */
+static const struct snd_kcontrol_new max98095_right_speaker_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_051_MIX_SPK_RIGHT, 6, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_051_MIX_SPK_RIGHT, 0, 1, 0),
+	SOC_DAPM_SINGLE("Mono DAC2 Switch", M98095_051_MIX_SPK_RIGHT, 3, 1, 0),
+	SOC_DAPM_SINGLE("Mono DAC3 Switch", M98095_051_MIX_SPK_RIGHT, 3, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_051_MIX_SPK_RIGHT, 5, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_051_MIX_SPK_RIGHT, 4, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_051_MIX_SPK_RIGHT, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_051_MIX_SPK_RIGHT, 2, 1, 0),
+};
+
+/* Left headphone mixer switch */
+static const struct snd_kcontrol_new max98095_left_hp_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_04C_MIX_HP_LEFT, 0, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_04C_MIX_HP_LEFT, 5, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_04C_MIX_HP_LEFT, 3, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_04C_MIX_HP_LEFT, 4, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_04C_MIX_HP_LEFT, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_04C_MIX_HP_LEFT, 2, 1, 0),
+};
+
+/* Right headphone mixer switch */
+static const struct snd_kcontrol_new max98095_right_hp_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_04D_MIX_HP_RIGHT, 5, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_04D_MIX_HP_RIGHT, 0, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_04D_MIX_HP_RIGHT, 3, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_04D_MIX_HP_RIGHT, 4, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_04D_MIX_HP_RIGHT, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_04D_MIX_HP_RIGHT, 2, 1, 0),
+};
+
+/* Receiver earpiece mixer switch */
+static const struct snd_kcontrol_new max98095_mono_rcv_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_04F_MIX_RCV, 0, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_04F_MIX_RCV, 5, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_04F_MIX_RCV, 3, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_04F_MIX_RCV, 4, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_04F_MIX_RCV, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_04F_MIX_RCV, 2, 1, 0),
+};
+
+/* Left lineout mixer switch */
+static const struct snd_kcontrol_new max98095_left_lineout_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_053_MIX_LINEOUT1, 5, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_053_MIX_LINEOUT1, 0, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_053_MIX_LINEOUT1, 3, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_053_MIX_LINEOUT1, 4, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_053_MIX_LINEOUT1, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_053_MIX_LINEOUT1, 2, 1, 0),
+};
+
+/* Right lineout mixer switch */
+static const struct snd_kcontrol_new max98095_right_lineout_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_054_MIX_LINEOUT2, 0, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_054_MIX_LINEOUT2, 5, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_054_MIX_LINEOUT2, 3, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_054_MIX_LINEOUT2, 4, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_054_MIX_LINEOUT2, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_054_MIX_LINEOUT2, 2, 1, 0),
+};
+
+/* Left ADC mixer switch */
+static const struct snd_kcontrol_new max98095_left_ADC_mixer_controls[] = {
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_04A_MIX_ADC_LEFT, 7, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_04A_MIX_ADC_LEFT, 6, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_04A_MIX_ADC_LEFT, 3, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_04A_MIX_ADC_LEFT, 2, 1, 0),
+};
+
+/* Right ADC mixer switch */
+static const struct snd_kcontrol_new max98095_right_ADC_mixer_controls[] = {
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_04B_MIX_ADC_RIGHT, 7, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_04B_MIX_ADC_RIGHT, 6, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_04B_MIX_ADC_RIGHT, 3, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_04B_MIX_ADC_RIGHT, 2, 1, 0),
+};
+
+static int max98095_mic_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (w->reg == M98095_05F_LVL_MIC1) {
+			snd_soc_update_bits(codec, w->reg, M98095_MICPRE_MASK,
+				(1+max98095->mic1pre)<<M98095_MICPRE_SHIFT);
+		} else {
+			snd_soc_update_bits(codec, w->reg, M98095_MICPRE_MASK,
+				(1+max98095->mic2pre)<<M98095_MICPRE_SHIFT);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, w->reg, M98095_MICPRE_MASK, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * The line inputs are stereo inputs with the left and right
+ * channels sharing a common PGA power control signal.
+ */
+static int max98095_line_pga(struct snd_soc_dapm_widget *w,
+			     int event, u8 channel)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	u8 *state;
+
+	BUG_ON(!((channel == 1) || (channel == 2)));
+
+	state = &max98095->lin_state;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		*state |= channel;
+		snd_soc_update_bits(codec, w->reg,
+			(1 << w->shift), (1 << w->shift));
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		*state &= ~channel;
+		if (*state == 0) {
+			snd_soc_update_bits(codec, w->reg,
+				(1 << w->shift), 0);
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int max98095_pga_in1_event(struct snd_soc_dapm_widget *w,
+				   struct snd_kcontrol *k, int event)
+{
+	return max98095_line_pga(w, event, 1);
+}
+
+static int max98095_pga_in2_event(struct snd_soc_dapm_widget *w,
+				   struct snd_kcontrol *k, int event)
+{
+	return max98095_line_pga(w, event, 2);
+}
+
+/*
+ * The stereo line out mixer outputs to two stereo line outs.
+ * The 2nd pair has a separate set of enables.
+ */
+static int max98095_lineout_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec, w->reg,
+			(1 << (w->shift+2)), (1 << (w->shift+2)));
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, w->reg,
+			(1 << (w->shift+2)), 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget max98095_dapm_widgets[] = {
+
+	SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", M98095_090_PWR_EN_IN, 0, 0),
+	SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", M98095_090_PWR_EN_IN, 1, 0),
+
+	SND_SOC_DAPM_DAC("DACL1", "HiFi Playback",
+		M98095_091_PWR_EN_OUT, 0, 0),
+	SND_SOC_DAPM_DAC("DACR1", "HiFi Playback",
+		M98095_091_PWR_EN_OUT, 1, 0),
+	SND_SOC_DAPM_DAC("DACM2", "Aux Playback",
+		M98095_091_PWR_EN_OUT, 2, 0),
+	SND_SOC_DAPM_DAC("DACM3", "Voice Playback",
+		M98095_091_PWR_EN_OUT, 2, 0),
+
+	SND_SOC_DAPM_PGA("HP Left Out", M98095_091_PWR_EN_OUT,
+		6, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HP Right Out", M98095_091_PWR_EN_OUT,
+		7, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("SPK Left Out", M98095_091_PWR_EN_OUT,
+		4, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SPK Right Out", M98095_091_PWR_EN_OUT,
+		5, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("RCV Mono Out", M98095_091_PWR_EN_OUT,
+		3, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA_E("LINE Left Out", M98095_092_PWR_EN_OUT,
+		0, 0, NULL, 0, max98095_lineout_event, SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_PGA_E("LINE Right Out", M98095_092_PWR_EN_OUT,
+		1, 0, NULL, 0, max98095_lineout_event, SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_MUX("External MIC", SND_SOC_NOPM, 0, 0,
+		&max98095_extmic_mux),
+
+	SND_SOC_DAPM_MUX("Linein Mux", SND_SOC_NOPM, 0, 0,
+		&max98095_linein_mux),
+
+	SND_SOC_DAPM_MIXER("Left Headphone Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_left_hp_mixer_controls[0],
+		ARRAY_SIZE(max98095_left_hp_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Right Headphone Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_right_hp_mixer_controls[0],
+		ARRAY_SIZE(max98095_right_hp_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Left Speaker Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_left_speaker_mixer_controls[0],
+		ARRAY_SIZE(max98095_left_speaker_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Right Speaker Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_right_speaker_mixer_controls[0],
+		ARRAY_SIZE(max98095_right_speaker_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Receiver Mixer", SND_SOC_NOPM, 0, 0,
+	  &max98095_mono_rcv_mixer_controls[0],
+		ARRAY_SIZE(max98095_mono_rcv_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Left Lineout Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_left_lineout_mixer_controls[0],
+		ARRAY_SIZE(max98095_left_lineout_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Right Lineout Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_right_lineout_mixer_controls[0],
+		ARRAY_SIZE(max98095_right_lineout_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_left_ADC_mixer_controls[0],
+		ARRAY_SIZE(max98095_left_ADC_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_right_ADC_mixer_controls[0],
+		ARRAY_SIZE(max98095_right_ADC_mixer_controls)),
+
+	SND_SOC_DAPM_PGA_E("MIC1 Input", M98095_05F_LVL_MIC1,
+		5, 0, NULL, 0, max98095_mic_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_PGA_E("MIC2 Input", M98095_060_LVL_MIC2,
+		5, 0, NULL, 0, max98095_mic_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_PGA_E("IN1 Input", M98095_090_PWR_EN_IN,
+		7, 0, NULL, 0, max98095_pga_in1_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_PGA_E("IN2 Input", M98095_090_PWR_EN_IN,
+		7, 0, NULL, 0, max98095_pga_in2_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MICBIAS("MICBIAS1", M98095_090_PWR_EN_IN, 2, 0),
+	SND_SOC_DAPM_MICBIAS("MICBIAS2", M98095_090_PWR_EN_IN, 3, 0),
+
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+	SND_SOC_DAPM_OUTPUT("SPKL"),
+	SND_SOC_DAPM_OUTPUT("SPKR"),
+	SND_SOC_DAPM_OUTPUT("RCV"),
+	SND_SOC_DAPM_OUTPUT("OUT1"),
+	SND_SOC_DAPM_OUTPUT("OUT2"),
+	SND_SOC_DAPM_OUTPUT("OUT3"),
+	SND_SOC_DAPM_OUTPUT("OUT4"),
+
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_INPUT("INA1"),
+	SND_SOC_DAPM_INPUT("INA2"),
+	SND_SOC_DAPM_INPUT("INB1"),
+	SND_SOC_DAPM_INPUT("INB2"),
+};
+
+static const struct snd_soc_dapm_route max98095_audio_map[] = {
+	/* Left headphone output mixer */
+	{"Left Headphone Mixer", "Left DAC1 Switch", "DACL1"},
+	{"Left Headphone Mixer", "Right DAC1 Switch", "DACR1"},
+	{"Left Headphone Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Left Headphone Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Left Headphone Mixer", "IN1 Switch", "IN1 Input"},
+	{"Left Headphone Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Right headphone output mixer */
+	{"Right Headphone Mixer", "Left DAC1 Switch", "DACL1"},
+	{"Right Headphone Mixer", "Right DAC1 Switch", "DACR1"},
+	{"Right Headphone Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Right Headphone Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Right Headphone Mixer", "IN1 Switch", "IN1 Input"},
+	{"Right Headphone Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Left speaker output mixer */
+	{"Left Speaker Mixer", "Left DAC1 Switch", "DACL1"},
+	{"Left Speaker Mixer", "Right DAC1 Switch", "DACR1"},
+	{"Left Speaker Mixer", "Mono DAC2 Switch", "DACM2"},
+	{"Left Speaker Mixer", "Mono DAC3 Switch", "DACM3"},
+	{"Left Speaker Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Left Speaker Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Left Speaker Mixer", "IN1 Switch", "IN1 Input"},
+	{"Left Speaker Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Right speaker output mixer */
+	{"Right Speaker Mixer", "Left DAC1 Switch", "DACL1"},
+	{"Right Speaker Mixer", "Right DAC1 Switch", "DACR1"},
+	{"Right Speaker Mixer", "Mono DAC2 Switch", "DACM2"},
+	{"Right Speaker Mixer", "Mono DAC3 Switch", "DACM3"},
+	{"Right Speaker Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Right Speaker Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Right Speaker Mixer", "IN1 Switch", "IN1 Input"},
+	{"Right Speaker Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Earpiece/Receiver output mixer */
+	{"Receiver Mixer", "Left DAC1 Switch", "DACL1"},
+	{"Receiver Mixer", "Right DAC1 Switch", "DACR1"},
+	{"Receiver Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Receiver Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Receiver Mixer", "IN1 Switch", "IN1 Input"},
+	{"Receiver Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Left Lineout output mixer */
+	{"Left Lineout Mixer", "Left DAC1 Switch", "DACL1"},
+	{"Left Lineout Mixer", "Right DAC1 Switch", "DACR1"},
+	{"Left Lineout Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Left Lineout Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Left Lineout Mixer", "IN1 Switch", "IN1 Input"},
+	{"Left Lineout Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Right lineout output mixer */
+	{"Right Lineout Mixer", "Left DAC1 Switch", "DACL1"},
+	{"Right Lineout Mixer", "Right DAC1 Switch", "DACR1"},
+	{"Right Lineout Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Right Lineout Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Right Lineout Mixer", "IN1 Switch", "IN1 Input"},
+	{"Right Lineout Mixer", "IN2 Switch", "IN2 Input"},
+
+	{"HP Left Out", NULL, "Left Headphone Mixer"},
+	{"HP Right Out", NULL, "Right Headphone Mixer"},
+	{"SPK Left Out", NULL, "Left Speaker Mixer"},
+	{"SPK Right Out", NULL, "Right Speaker Mixer"},
+	{"RCV Mono Out", NULL, "Receiver Mixer"},
+	{"LINE Left Out", NULL, "Left Lineout Mixer"},
+	{"LINE Right Out", NULL, "Right Lineout Mixer"},
+
+	{"HPL", NULL, "HP Left Out"},
+	{"HPR", NULL, "HP Right Out"},
+	{"SPKL", NULL, "SPK Left Out"},
+	{"SPKR", NULL, "SPK Right Out"},
+	{"RCV", NULL, "RCV Mono Out"},
+	{"OUT1", NULL, "LINE Left Out"},
+	{"OUT2", NULL, "LINE Right Out"},
+	{"OUT3", NULL, "LINE Left Out"},
+	{"OUT4", NULL, "LINE Right Out"},
+
+	/* Left ADC input mixer */
+	{"Left ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Left ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Left ADC Mixer", "IN1 Switch", "IN1 Input"},
+	{"Left ADC Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Right ADC input mixer */
+	{"Right ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Right ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Right ADC Mixer", "IN1 Switch", "IN1 Input"},
+	{"Right ADC Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Inputs */
+	{"ADCL", NULL, "Left ADC Mixer"},
+	{"ADCR", NULL, "Right ADC Mixer"},
+
+	{"IN1 Input", NULL, "INA1"},
+	{"IN2 Input", NULL, "INA2"},
+
+	{"MIC1 Input", NULL, "MIC1"},
+	{"MIC2 Input", NULL, "MIC2"},
+};
+
+static int max98095_add_widgets(struct snd_soc_codec *codec)
+{
+	snd_soc_add_controls(codec, max98095_snd_controls,
+			     ARRAY_SIZE(max98095_snd_controls));
+
+	return 0;
+}
+
+/* codec mclk clock divider coefficients */
+static const struct {
+	u32 rate;
+	u8  sr;
+} rate_table[] = {
+	{8000,  0x01},
+	{11025, 0x02},
+	{16000, 0x03},
+	{22050, 0x04},
+	{24000, 0x05},
+	{32000, 0x06},
+	{44100, 0x07},
+	{48000, 0x08},
+	{88200, 0x09},
+	{96000, 0x0A},
+};
+
+static int rate_value(int rate, u8 *value)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
+		if (rate_table[i].rate >= rate) {
+			*value = rate_table[i].sr;
+			return 0;
+		}
+	}
+	*value = rate_table[0].sr;
+	return -EINVAL;
+}
+
+static int max98095_dai1_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params,
+				   struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_cdata *cdata;
+	unsigned long long ni;
+	unsigned int rate;
+	u8 regval;
+
+	cdata = &max98095->dai[0];
+
+	rate = params_rate(params);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		snd_soc_update_bits(codec, M98095_02A_DAI1_FORMAT,
+			M98095_DAI_WS, 0);
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		snd_soc_update_bits(codec, M98095_02A_DAI1_FORMAT,
+			M98095_DAI_WS, M98095_DAI_WS);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (rate_value(rate, &regval))
+		return -EINVAL;
+
+	snd_soc_update_bits(codec, M98095_027_DAI1_CLKMODE,
+		M98095_CLKMODE_MASK, regval);
+	cdata->rate = rate;
+
+	/* Configure NI when operating as master */
+	if (snd_soc_read(codec, M98095_02A_DAI1_FORMAT) & M98095_DAI_MAS) {
+		if (max98095->sysclk == 0) {
+			dev_err(codec->dev, "Invalid system clock frequency\n");
+			return -EINVAL;
+		}
+		ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+				* (unsigned long long int)rate;
+		do_div(ni, (unsigned long long int)max98095->sysclk);
+		snd_soc_write(codec, M98095_028_DAI1_CLKCFG_HI,
+			(ni >> 8) & 0x7F);
+		snd_soc_write(codec, M98095_029_DAI1_CLKCFG_LO,
+			ni & 0xFF);
+	}
+
+	/* Update sample rate mode */
+	if (rate < 50000)
+		snd_soc_update_bits(codec, M98095_02E_DAI1_FILTERS,
+			M98095_DAI_DHF, 0);
+	else
+		snd_soc_update_bits(codec, M98095_02E_DAI1_FILTERS,
+			M98095_DAI_DHF, M98095_DAI_DHF);
+
+	return 0;
+}
+
+static int max98095_dai2_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params,
+				   struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_cdata *cdata;
+	unsigned long long ni;
+	unsigned int rate;
+	u8 regval;
+
+	cdata = &max98095->dai[1];
+
+	rate = params_rate(params);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		snd_soc_update_bits(codec, M98095_034_DAI2_FORMAT,
+			M98095_DAI_WS, 0);
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		snd_soc_update_bits(codec, M98095_034_DAI2_FORMAT,
+			M98095_DAI_WS, M98095_DAI_WS);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (rate_value(rate, &regval))
+		return -EINVAL;
+
+	snd_soc_update_bits(codec, M98095_031_DAI2_CLKMODE,
+		M98095_CLKMODE_MASK, regval);
+	cdata->rate = rate;
+
+	/* Configure NI when operating as master */
+	if (snd_soc_read(codec, M98095_034_DAI2_FORMAT) & M98095_DAI_MAS) {
+		if (max98095->sysclk == 0) {
+			dev_err(codec->dev, "Invalid system clock frequency\n");
+			return -EINVAL;
+		}
+		ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+				* (unsigned long long int)rate;
+		do_div(ni, (unsigned long long int)max98095->sysclk);
+		snd_soc_write(codec, M98095_032_DAI2_CLKCFG_HI,
+			(ni >> 8) & 0x7F);
+		snd_soc_write(codec, M98095_033_DAI2_CLKCFG_LO,
+			ni & 0xFF);
+	}
+
+	/* Update sample rate mode */
+	if (rate < 50000)
+		snd_soc_update_bits(codec, M98095_038_DAI2_FILTERS,
+			M98095_DAI_DHF, 0);
+	else
+		snd_soc_update_bits(codec, M98095_038_DAI2_FILTERS,
+			M98095_DAI_DHF, M98095_DAI_DHF);
+
+	return 0;
+}
+
+static int max98095_dai3_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params,
+				   struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_cdata *cdata;
+	unsigned long long ni;
+	unsigned int rate;
+	u8 regval;
+
+	cdata = &max98095->dai[2];
+
+	rate = params_rate(params);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		snd_soc_update_bits(codec, M98095_03E_DAI3_FORMAT,
+			M98095_DAI_WS, 0);
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		snd_soc_update_bits(codec, M98095_03E_DAI3_FORMAT,
+			M98095_DAI_WS, M98095_DAI_WS);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (rate_value(rate, &regval))
+		return -EINVAL;
+
+	snd_soc_update_bits(codec, M98095_03B_DAI3_CLKMODE,
+		M98095_CLKMODE_MASK, regval);
+	cdata->rate = rate;
+
+	/* Configure NI when operating as master */
+	if (snd_soc_read(codec, M98095_03E_DAI3_FORMAT) & M98095_DAI_MAS) {
+		if (max98095->sysclk == 0) {
+			dev_err(codec->dev, "Invalid system clock frequency\n");
+			return -EINVAL;
+		}
+		ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+				* (unsigned long long int)rate;
+		do_div(ni, (unsigned long long int)max98095->sysclk);
+		snd_soc_write(codec, M98095_03C_DAI3_CLKCFG_HI,
+			(ni >> 8) & 0x7F);
+		snd_soc_write(codec, M98095_03D_DAI3_CLKCFG_LO,
+			ni & 0xFF);
+	}
+
+	/* Update sample rate mode */
+	if (rate < 50000)
+		snd_soc_update_bits(codec, M98095_042_DAI3_FILTERS,
+			M98095_DAI_DHF, 0);
+	else
+		snd_soc_update_bits(codec, M98095_042_DAI3_FILTERS,
+			M98095_DAI_DHF, M98095_DAI_DHF);
+
+	return 0;
+}
+
+static int max98095_dai_set_sysclk(struct snd_soc_dai *dai,
+				   int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+
+	/* Requested clock frequency is already setup */
+	if (freq == max98095->sysclk)
+		return 0;
+
+	max98095->sysclk = freq; /* remember current sysclk */
+
+	/* Setup clocks for slave mode, and using the PLL
+	 * PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
+	 *         0x02 (when master clk is 20MHz to 40MHz)..
+	 *         0x03 (when master clk is 40MHz to 60MHz)..
+	 */
+	if ((freq >= 10000000) && (freq < 20000000)) {
+		snd_soc_write(codec, M98095_026_SYS_CLK, 0x10);
+	} else if ((freq >= 20000000) && (freq < 40000000)) {
+		snd_soc_write(codec, M98095_026_SYS_CLK, 0x20);
+	} else if ((freq >= 40000000) && (freq < 60000000)) {
+		snd_soc_write(codec, M98095_026_SYS_CLK, 0x30);
+	} else {
+		dev_err(codec->dev, "Invalid master clock frequency\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq);
+
+	max98095->sysclk = freq;
+	return 0;
+}
+
+static int max98095_dai1_set_fmt(struct snd_soc_dai *codec_dai,
+				 unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_cdata *cdata;
+	u8 regval = 0;
+
+	cdata = &max98095->dai[0];
+
+	if (fmt != cdata->fmt) {
+		cdata->fmt = fmt;
+
+		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+		case SND_SOC_DAIFMT_CBS_CFS:
+			/* Slave mode PLL */
+			snd_soc_write(codec, M98095_028_DAI1_CLKCFG_HI,
+				0x80);
+			snd_soc_write(codec, M98095_029_DAI1_CLKCFG_LO,
+				0x00);
+			break;
+		case SND_SOC_DAIFMT_CBM_CFM:
+			/* Set to master mode */
+			regval |= M98095_DAI_MAS;
+			break;
+		case SND_SOC_DAIFMT_CBS_CFM:
+		case SND_SOC_DAIFMT_CBM_CFS:
+		default:
+			dev_err(codec->dev, "Clock mode unsupported");
+			return -EINVAL;
+		}
+
+		switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+		case SND_SOC_DAIFMT_I2S:
+			regval |= M98095_DAI_DLY;
+			break;
+		case SND_SOC_DAIFMT_LEFT_J:
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			regval |= M98095_DAI_WCI;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			regval |= M98095_DAI_BCI;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			regval |= M98095_DAI_BCI|M98095_DAI_WCI;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		snd_soc_update_bits(codec, M98095_02A_DAI1_FORMAT,
+			M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI |
+			M98095_DAI_WCI, regval);
+
+		snd_soc_write(codec, M98095_02B_DAI1_CLOCK, M98095_DAI_BSEL64);
+	}
+
+	return 0;
+}
+
+static int max98095_dai2_set_fmt(struct snd_soc_dai *codec_dai,
+				 unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_cdata *cdata;
+	u8 regval = 0;
+
+	cdata = &max98095->dai[1];
+
+	if (fmt != cdata->fmt) {
+		cdata->fmt = fmt;
+
+		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+		case SND_SOC_DAIFMT_CBS_CFS:
+			/* Slave mode PLL */
+			snd_soc_write(codec, M98095_032_DAI2_CLKCFG_HI,
+				0x80);
+			snd_soc_write(codec, M98095_033_DAI2_CLKCFG_LO,
+				0x00);
+			break;
+		case SND_SOC_DAIFMT_CBM_CFM:
+			/* Set to master mode */
+			regval |= M98095_DAI_MAS;
+			break;
+		case SND_SOC_DAIFMT_CBS_CFM:
+		case SND_SOC_DAIFMT_CBM_CFS:
+		default:
+			dev_err(codec->dev, "Clock mode unsupported");
+			return -EINVAL;
+		}
+
+		switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+		case SND_SOC_DAIFMT_I2S:
+			regval |= M98095_DAI_DLY;
+			break;
+		case SND_SOC_DAIFMT_LEFT_J:
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			regval |= M98095_DAI_WCI;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			regval |= M98095_DAI_BCI;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			regval |= M98095_DAI_BCI|M98095_DAI_WCI;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		snd_soc_update_bits(codec, M98095_034_DAI2_FORMAT,
+			M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI |
+			M98095_DAI_WCI, regval);
+
+		snd_soc_write(codec, M98095_035_DAI2_CLOCK,
+			M98095_DAI_BSEL64);
+	}
+
+	return 0;
+}
+
+static int max98095_dai3_set_fmt(struct snd_soc_dai *codec_dai,
+				 unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_cdata *cdata;
+	u8 regval = 0;
+
+	cdata = &max98095->dai[2];
+
+	if (fmt != cdata->fmt) {
+		cdata->fmt = fmt;
+
+		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+		case SND_SOC_DAIFMT_CBS_CFS:
+			/* Slave mode PLL */
+			snd_soc_write(codec, M98095_03C_DAI3_CLKCFG_HI,
+				0x80);
+			snd_soc_write(codec, M98095_03D_DAI3_CLKCFG_LO,
+				0x00);
+			break;
+		case SND_SOC_DAIFMT_CBM_CFM:
+			/* Set to master mode */
+			regval |= M98095_DAI_MAS;
+			break;
+		case SND_SOC_DAIFMT_CBS_CFM:
+		case SND_SOC_DAIFMT_CBM_CFS:
+		default:
+			dev_err(codec->dev, "Clock mode unsupported");
+			return -EINVAL;
+		}
+
+		switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+		case SND_SOC_DAIFMT_I2S:
+			regval |= M98095_DAI_DLY;
+			break;
+		case SND_SOC_DAIFMT_LEFT_J:
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			regval |= M98095_DAI_WCI;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			regval |= M98095_DAI_BCI;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			regval |= M98095_DAI_BCI|M98095_DAI_WCI;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		snd_soc_update_bits(codec, M98095_03E_DAI3_FORMAT,
+			M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI |
+			M98095_DAI_WCI, regval);
+
+		snd_soc_write(codec, M98095_03F_DAI3_CLOCK,
+			M98095_DAI_BSEL64);
+	}
+
+	return 0;
+}
+
+static int max98095_set_bias_level(struct snd_soc_codec *codec,
+				   enum snd_soc_bias_level level)
+{
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			ret = snd_soc_cache_sync(codec);
+
+			if (ret != 0) {
+				dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
+				return ret;
+			}
+		}
+
+		snd_soc_update_bits(codec, M98095_090_PWR_EN_IN,
+				M98095_MBEN, M98095_MBEN);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_update_bits(codec, M98095_090_PWR_EN_IN,
+				M98095_MBEN, 0);
+		codec->cache_sync = 1;
+		break;
+	}
+	codec->dapm.bias_level = level;
+	return 0;
+}
+
+#define MAX98095_RATES SNDRV_PCM_RATE_8000_96000
+#define MAX98095_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops max98095_dai1_ops = {
+	.set_sysclk = max98095_dai_set_sysclk,
+	.set_fmt = max98095_dai1_set_fmt,
+	.hw_params = max98095_dai1_hw_params,
+};
+
+static struct snd_soc_dai_ops max98095_dai2_ops = {
+	.set_sysclk = max98095_dai_set_sysclk,
+	.set_fmt = max98095_dai2_set_fmt,
+	.hw_params = max98095_dai2_hw_params,
+};
+
+static struct snd_soc_dai_ops max98095_dai3_ops = {
+	.set_sysclk = max98095_dai_set_sysclk,
+	.set_fmt = max98095_dai3_set_fmt,
+	.hw_params = max98095_dai3_hw_params,
+};
+
+static struct snd_soc_dai_driver max98095_dai[] = {
+{
+	.name = "HiFi",
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = MAX98095_RATES,
+		.formats = MAX98095_FORMATS,
+	},
+	.capture = {
+		.stream_name = "HiFi Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = MAX98095_RATES,
+		.formats = MAX98095_FORMATS,
+	},
+	 .ops = &max98095_dai1_ops,
+},
+{
+	.name = "Aux",
+	.playback = {
+		.stream_name = "Aux Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = MAX98095_RATES,
+		.formats = MAX98095_FORMATS,
+	},
+	.ops = &max98095_dai2_ops,
+},
+{
+	.name = "Voice",
+	.playback = {
+		.stream_name = "Voice Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = MAX98095_RATES,
+		.formats = MAX98095_FORMATS,
+	},
+	.ops = &max98095_dai3_ops,
+}
+
+};
+
+static int max98095_get_eq_channel(const char *name)
+{
+	if (strcmp(name, "EQ1 Mode") == 0)
+		return 0;
+	if (strcmp(name, "EQ2 Mode") == 0)
+		return 1;
+	return -EINVAL;
+}
+
+static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_pdata *pdata = max98095->pdata;
+	int channel = max98095_get_eq_channel(kcontrol->id.name);
+	struct max98095_cdata *cdata;
+	int sel = ucontrol->value.integer.value[0];
+	struct max98095_eq_cfg *coef_set;
+	int fs, best, best_val, i;
+	int regmask, regsave;
+
+	BUG_ON(channel > 1);
+
+	if (!pdata || !max98095->eq_textcnt)
+		return 0;
+
+	if (sel >= pdata->eq_cfgcnt)
+		return -EINVAL;
+
+	cdata = &max98095->dai[channel];
+	cdata->eq_sel = sel;
+	fs = cdata->rate;
+
+	/* Find the selected configuration with nearest sample rate */
+	best = 0;
+	best_val = INT_MAX;
+	for (i = 0; i < pdata->eq_cfgcnt; i++) {
+		if (strcmp(pdata->eq_cfg[i].name, max98095->eq_texts[sel]) == 0 &&
+			abs(pdata->eq_cfg[i].rate - fs) < best_val) {
+			best = i;
+			best_val = abs(pdata->eq_cfg[i].rate - fs);
+		}
+	}
+
+	dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+		pdata->eq_cfg[best].name,
+		pdata->eq_cfg[best].rate, fs);
+
+	coef_set = &pdata->eq_cfg[best];
+
+	regmask = (channel == 0) ? M98095_EQ1EN : M98095_EQ2EN;
+
+	/* Disable filter while configuring, and save current on/off state */
+	regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL);
+	snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0);
+
+	mutex_lock(&codec->mutex);
+	snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
+	m98095_eq_band(codec, channel, 0, coef_set->band1);
+	m98095_eq_band(codec, channel, 1, coef_set->band2);
+	m98095_eq_band(codec, channel, 2, coef_set->band3);
+	m98095_eq_band(codec, channel, 3, coef_set->band4);
+	m98095_eq_band(codec, channel, 4, coef_set->band5);
+	snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0);
+	mutex_unlock(&codec->mutex);
+
+	/* Restore the original on/off state */
+	snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave);
+	return 0;
+}
+
+static int max98095_get_eq_enum(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	int channel = max98095_get_eq_channel(kcontrol->id.name);
+	struct max98095_cdata *cdata;
+
+	cdata = &max98095->dai[channel];
+	ucontrol->value.enumerated.item[0] = cdata->eq_sel;
+
+	return 0;
+}
+
+static void max98095_handle_eq_pdata(struct snd_soc_codec *codec)
+{
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_pdata *pdata = max98095->pdata;
+	struct max98095_eq_cfg *cfg;
+	unsigned int cfgcnt;
+	int i, j;
+	const char **t;
+	int ret;
+
+	struct snd_kcontrol_new controls[] = {
+		SOC_ENUM_EXT("EQ1 Mode",
+			max98095->eq_enum,
+			max98095_get_eq_enum,
+			max98095_put_eq_enum),
+		SOC_ENUM_EXT("EQ2 Mode",
+			max98095->eq_enum,
+			max98095_get_eq_enum,
+			max98095_put_eq_enum),
+	};
+
+	cfg = pdata->eq_cfg;
+	cfgcnt = pdata->eq_cfgcnt;
+
+	/* Setup an array of texts for the equalizer enum.
+	 * This is based on Mark Brown's equalizer driver code.
+	 */
+	max98095->eq_textcnt = 0;
+	max98095->eq_texts = NULL;
+	for (i = 0; i < cfgcnt; i++) {
+		for (j = 0; j < max98095->eq_textcnt; j++) {
+			if (strcmp(cfg[i].name, max98095->eq_texts[j]) == 0)
+				break;
+		}
+
+		if (j != max98095->eq_textcnt)
+			continue;
+
+		/* Expand the array */
+		t = krealloc(max98095->eq_texts,
+			     sizeof(char *) * (max98095->eq_textcnt + 1),
+			     GFP_KERNEL);
+		if (t == NULL)
+			continue;
+
+		/* Store the new entry */
+		t[max98095->eq_textcnt] = cfg[i].name;
+		max98095->eq_textcnt++;
+		max98095->eq_texts = t;
+	}
+
+	/* Now point the soc_enum to .texts array items */
+	max98095->eq_enum.texts = max98095->eq_texts;
+	max98095->eq_enum.max = max98095->eq_textcnt;
+
+	ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls));
+	if (ret != 0)
+		dev_err(codec->dev, "Failed to add EQ control: %d\n", ret);
+}
+
+static int max98095_get_bq_channel(const char *name)
+{
+	if (strcmp(name, "Biquad1 Mode") == 0)
+		return 0;
+	if (strcmp(name, "Biquad2 Mode") == 0)
+		return 1;
+	return -EINVAL;
+}
+
+static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_pdata *pdata = max98095->pdata;
+	int channel = max98095_get_bq_channel(kcontrol->id.name);
+	struct max98095_cdata *cdata;
+	int sel = ucontrol->value.integer.value[0];
+	struct max98095_biquad_cfg *coef_set;
+	int fs, best, best_val, i;
+	int regmask, regsave;
+
+	BUG_ON(channel > 1);
+
+	if (!pdata || !max98095->bq_textcnt)
+		return 0;
+
+	if (sel >= pdata->bq_cfgcnt)
+		return -EINVAL;
+
+	cdata = &max98095->dai[channel];
+	cdata->bq_sel = sel;
+	fs = cdata->rate;
+
+	/* Find the selected configuration with nearest sample rate */
+	best = 0;
+	best_val = INT_MAX;
+	for (i = 0; i < pdata->bq_cfgcnt; i++) {
+		if (strcmp(pdata->bq_cfg[i].name, max98095->bq_texts[sel]) == 0 &&
+			abs(pdata->bq_cfg[i].rate - fs) < best_val) {
+			best = i;
+			best_val = abs(pdata->bq_cfg[i].rate - fs);
+		}
+	}
+
+	dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+		pdata->bq_cfg[best].name,
+		pdata->bq_cfg[best].rate, fs);
+
+	coef_set = &pdata->bq_cfg[best];
+
+	regmask = (channel == 0) ? M98095_BQ1EN : M98095_BQ2EN;
+
+	/* Disable filter while configuring, and save current on/off state */
+	regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL);
+	snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0);
+
+	mutex_lock(&codec->mutex);
+	snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
+	m98095_biquad_band(codec, channel, 0, coef_set->band1);
+	m98095_biquad_band(codec, channel, 1, coef_set->band2);
+	snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0);
+	mutex_unlock(&codec->mutex);
+
+	/* Restore the original on/off state */
+	snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave);
+	return 0;
+}
+
+static int max98095_get_bq_enum(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	int channel = max98095_get_bq_channel(kcontrol->id.name);
+	struct max98095_cdata *cdata;
+
+	cdata = &max98095->dai[channel];
+	ucontrol->value.enumerated.item[0] = cdata->bq_sel;
+
+	return 0;
+}
+
+static void max98095_handle_bq_pdata(struct snd_soc_codec *codec)
+{
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_pdata *pdata = max98095->pdata;
+	struct max98095_biquad_cfg *cfg;
+	unsigned int cfgcnt;
+	int i, j;
+	const char **t;
+	int ret;
+
+	struct snd_kcontrol_new controls[] = {
+		SOC_ENUM_EXT("Biquad1 Mode",
+			max98095->bq_enum,
+			max98095_get_bq_enum,
+			max98095_put_bq_enum),
+		SOC_ENUM_EXT("Biquad2 Mode",
+			max98095->bq_enum,
+			max98095_get_bq_enum,
+			max98095_put_bq_enum),
+	};
+
+	cfg = pdata->bq_cfg;
+	cfgcnt = pdata->bq_cfgcnt;
+
+	/* Setup an array of texts for the biquad enum.
+	 * This is based on Mark Brown's equalizer driver code.
+	 */
+	max98095->bq_textcnt = 0;
+	max98095->bq_texts = NULL;
+	for (i = 0; i < cfgcnt; i++) {
+		for (j = 0; j < max98095->bq_textcnt; j++) {
+			if (strcmp(cfg[i].name, max98095->bq_texts[j]) == 0)
+				break;
+		}
+
+		if (j != max98095->bq_textcnt)
+			continue;
+
+		/* Expand the array */
+		t = krealloc(max98095->bq_texts,
+			     sizeof(char *) * (max98095->bq_textcnt + 1),
+			     GFP_KERNEL);
+		if (t == NULL)
+			continue;
+
+		/* Store the new entry */
+		t[max98095->bq_textcnt] = cfg[i].name;
+		max98095->bq_textcnt++;
+		max98095->bq_texts = t;
+	}
+
+	/* Now point the soc_enum to .texts array items */
+	max98095->bq_enum.texts = max98095->bq_texts;
+	max98095->bq_enum.max = max98095->bq_textcnt;
+
+	ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls));
+	if (ret != 0)
+		dev_err(codec->dev, "Failed to add Biquad control: %d\n", ret);
+}
+
+static void max98095_handle_pdata(struct snd_soc_codec *codec)
+{
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_pdata *pdata = max98095->pdata;
+	u8 regval = 0;
+
+	if (!pdata) {
+		dev_dbg(codec->dev, "No platform data\n");
+		return;
+	}
+
+	/* Configure mic for analog/digital mic mode */
+	if (pdata->digmic_left_mode)
+		regval |= M98095_DIGMIC_L;
+
+	if (pdata->digmic_right_mode)
+		regval |= M98095_DIGMIC_R;
+
+	snd_soc_write(codec, M98095_087_CFG_MIC, regval);
+
+	/* Configure equalizers */
+	if (pdata->eq_cfgcnt)
+		max98095_handle_eq_pdata(codec);
+
+	/* Configure bi-quad filters */
+	if (pdata->bq_cfgcnt)
+		max98095_handle_bq_pdata(codec);
+}
+
+#ifdef CONFIG_PM
+static int max98095_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+	max98095_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static int max98095_resume(struct snd_soc_codec *codec)
+{
+	max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	return 0;
+}
+#else
+#define max98095_suspend NULL
+#define max98095_resume NULL
+#endif
+
+static int max98095_reset(struct snd_soc_codec *codec)
+{
+	int i, ret;
+
+	/* Gracefully reset the DSP core and the codec hardware
+	 * in a proper sequence */
+	ret = snd_soc_write(codec, M98095_00F_HOST_CFG, 0);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to reset DSP: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_write(codec, M98095_097_PWR_SYS, 0);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to reset codec: %d\n", ret);
+		return ret;
+	}
+
+	/* Reset to hardware default for registers, as there is not
+	 * a soft reset hardware control register */
+	for (i = M98095_010_HOST_INT_CFG; i < M98095_REG_MAX_CACHED; i++) {
+		ret = snd_soc_write(codec, i, max98095_reg_def[i]);
+		if (ret < 0) {
+			dev_err(codec->dev, "Failed to reset: %d\n", ret);
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int max98095_probe(struct snd_soc_codec *codec)
+{
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_cdata *cdata;
+	int ret = 0;
+
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
+
+	/* reset the codec, the DSP core, and disable all interrupts */
+	max98095_reset(codec);
+
+	/* initialize private data */
+
+	max98095->sysclk = (unsigned)-1;
+	max98095->eq_textcnt = 0;
+	max98095->bq_textcnt = 0;
+
+	cdata = &max98095->dai[0];
+	cdata->rate = (unsigned)-1;
+	cdata->fmt  = (unsigned)-1;
+	cdata->eq_sel = 0;
+	cdata->bq_sel = 0;
+
+	cdata = &max98095->dai[1];
+	cdata->rate = (unsigned)-1;
+	cdata->fmt  = (unsigned)-1;
+	cdata->eq_sel = 0;
+	cdata->bq_sel = 0;
+
+	cdata = &max98095->dai[2];
+	cdata->rate = (unsigned)-1;
+	cdata->fmt  = (unsigned)-1;
+	cdata->eq_sel = 0;
+	cdata->bq_sel = 0;
+
+	max98095->lin_state = 0;
+	max98095->mic1pre = 0;
+	max98095->mic2pre = 0;
+
+	ret = snd_soc_read(codec, M98095_0FF_REV_ID);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to read device revision: %d\n",
+			ret);
+		goto err_access;
+	}
+	dev_info(codec->dev, "revision %c\n", ret + 'A');
+
+	snd_soc_write(codec, M98095_097_PWR_SYS, M98095_PWRSV);
+
+	/* initialize registers cache to hardware default */
+	max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	snd_soc_write(codec, M98095_048_MIX_DAC_LR,
+		M98095_DAI1L_TO_DACL|M98095_DAI1R_TO_DACR);
+
+	snd_soc_write(codec, M98095_049_MIX_DAC_M,
+		M98095_DAI2M_TO_DACM|M98095_DAI3M_TO_DACM);
+
+	snd_soc_write(codec, M98095_092_PWR_EN_OUT, M98095_SPK_SPREADSPECTRUM);
+	snd_soc_write(codec, M98095_045_CFG_DSP, M98095_DSPNORMAL);
+	snd_soc_write(codec, M98095_04E_CFG_HP, M98095_HPNORMAL);
+
+	snd_soc_write(codec, M98095_02C_DAI1_IOCFG,
+		M98095_S1NORMAL|M98095_SDATA);
+
+	snd_soc_write(codec, M98095_036_DAI2_IOCFG,
+		M98095_S2NORMAL|M98095_SDATA);
+
+	snd_soc_write(codec, M98095_040_DAI3_IOCFG,
+		M98095_S3NORMAL|M98095_SDATA);
+
+	max98095_handle_pdata(codec);
+
+	/* take the codec out of the shut down */
+	snd_soc_update_bits(codec, M98095_097_PWR_SYS, M98095_SHDNRUN,
+		M98095_SHDNRUN);
+
+	max98095_add_widgets(codec);
+
+err_access:
+	return ret;
+}
+
+static int max98095_remove(struct snd_soc_codec *codec)
+{
+	max98095_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_max98095 = {
+	.probe   = max98095_probe,
+	.remove  = max98095_remove,
+	.suspend = max98095_suspend,
+	.resume  = max98095_resume,
+	.set_bias_level = max98095_set_bias_level,
+	.reg_cache_size = ARRAY_SIZE(max98095_reg_def),
+	.reg_word_size = sizeof(u8),
+	.reg_cache_default = max98095_reg_def,
+	.readable_register = max98095_readable,
+	.volatile_register = max98095_volatile,
+	.dapm_widgets	  = max98095_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(max98095_dapm_widgets),
+	.dapm_routes     = max98095_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(max98095_audio_map),
+};
+
+static int max98095_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	struct max98095_priv *max98095;
+	int ret;
+
+	max98095 = kzalloc(sizeof(struct max98095_priv), GFP_KERNEL);
+	if (max98095 == NULL)
+		return -ENOMEM;
+
+	max98095->devtype = id->driver_data;
+	i2c_set_clientdata(i2c, max98095);
+	max98095->control_data = i2c;
+	max98095->pdata = i2c->dev.platform_data;
+
+	ret = snd_soc_register_codec(&i2c->dev,
+			&soc_codec_dev_max98095, &max98095_dai[0], 3);
+	if (ret < 0)
+		kfree(max98095);
+	return ret;
+}
+
+static int __devexit max98095_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	kfree(i2c_get_clientdata(client));
+
+	return 0;
+}
+
+static const struct i2c_device_id max98095_i2c_id[] = {
+	{ "max98095", MAX98095 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max98095_i2c_id);
+
+static struct i2c_driver max98095_i2c_driver = {
+	.driver = {
+		.name = "max98095",
+		.owner = THIS_MODULE,
+	},
+	.probe  = max98095_i2c_probe,
+	.remove = __devexit_p(max98095_i2c_remove),
+	.id_table = max98095_i2c_id,
+};
+
+static int __init max98095_init(void)
+{
+	int ret;
+
+	ret = i2c_add_driver(&max98095_i2c_driver);
+	if (ret)
+		pr_err("Failed to register max98095 I2C driver: %d\n", ret);
+
+	return ret;
+}
+module_init(max98095_init);
+
+static void __exit max98095_exit(void)
+{
+	i2c_del_driver(&max98095_i2c_driver);
+}
+module_exit(max98095_exit);
+
+MODULE_DESCRIPTION("ALSA SoC MAX98095 driver");
+MODULE_AUTHOR("Peter Hsiang");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98095.h b/sound/soc/codecs/max98095.h
new file mode 100644
index 000000000000..891584a0eb03
--- /dev/null
+++ b/sound/soc/codecs/max98095.h
@@ -0,0 +1,299 @@
+/*
+ * max98095.h -- MAX98095 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Maxim Integrated Products
+ *
+ * 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 _MAX98095_H
+#define _MAX98095_H
+
+/*
+ * MAX98095 Registers Definition
+ */
+
+#define M98095_000_HOST_DATA                0x00
+#define M98095_001_HOST_INT_STS             0x01
+#define M98095_002_HOST_RSP_STS             0x02
+#define M98095_003_HOST_CMD_STS             0x03
+#define M98095_004_CODEC_STS                0x04
+#define M98095_005_DAI1_ALC_STS             0x05
+#define M98095_006_DAI2_ALC_STS             0x06
+#define M98095_007_JACK_AUTO_STS            0x07
+#define M98095_008_JACK_MANUAL_STS          0x08
+#define M98095_009_JACK_VBAT_STS            0x09
+#define M98095_00A_ACC_ADC_STS              0x0A
+#define M98095_00B_MIC_NG_AGC_STS           0x0B
+#define M98095_00C_SPK_L_VOLT_STS           0x0C
+#define M98095_00D_SPK_R_VOLT_STS           0x0D
+#define M98095_00E_TEMP_SENSOR_STS          0x0E
+#define M98095_00F_HOST_CFG                 0x0F
+#define M98095_010_HOST_INT_CFG             0x10
+#define M98095_011_HOST_INT_EN              0x11
+#define M98095_012_CODEC_INT_EN             0x12
+#define M98095_013_JACK_INT_EN              0x13
+#define M98095_014_JACK_INT_EN              0x14
+#define M98095_015_DEC                      0x15
+#define M98095_016_RESERVED                 0x16
+#define M98095_017_RESERVED                 0x17
+#define M98095_018_KEYCODE3                 0x18
+#define M98095_019_KEYCODE2                 0x19
+#define M98095_01A_KEYCODE1                 0x1A
+#define M98095_01B_KEYCODE0                 0x1B
+#define M98095_01C_OEMCODE1                 0x1C
+#define M98095_01D_OEMCODE0                 0x1D
+#define M98095_01E_XCFG1                    0x1E
+#define M98095_01F_XCFG2                    0x1F
+#define M98095_020_XCFG3                    0x20
+#define M98095_021_XCFG4                    0x21
+#define M98095_022_XCFG5                    0x22
+#define M98095_023_XCFG6                    0x23
+#define M98095_024_XGPIO                    0x24
+#define M98095_025_XCLKCFG                  0x25
+#define M98095_026_SYS_CLK                  0x26
+#define M98095_027_DAI1_CLKMODE             0x27
+#define M98095_028_DAI1_CLKCFG_HI           0x28
+#define M98095_029_DAI1_CLKCFG_LO           0x29
+#define M98095_02A_DAI1_FORMAT              0x2A
+#define M98095_02B_DAI1_CLOCK               0x2B
+#define M98095_02C_DAI1_IOCFG               0x2C
+#define M98095_02D_DAI1_TDM                 0x2D
+#define M98095_02E_DAI1_FILTERS             0x2E
+#define M98095_02F_DAI1_LVL1                0x2F
+#define M98095_030_DAI1_LVL2                0x30
+#define M98095_031_DAI2_CLKMODE             0x31
+#define M98095_032_DAI2_CLKCFG_HI           0x32
+#define M98095_033_DAI2_CLKCFG_LO           0x33
+#define M98095_034_DAI2_FORMAT              0x34
+#define M98095_035_DAI2_CLOCK               0x35
+#define M98095_036_DAI2_IOCFG               0x36
+#define M98095_037_DAI2_TDM                 0x37
+#define M98095_038_DAI2_FILTERS             0x38
+#define M98095_039_DAI2_LVL1                0x39
+#define M98095_03A_DAI2_LVL2                0x3A
+#define M98095_03B_DAI3_CLKMODE             0x3B
+#define M98095_03C_DAI3_CLKCFG_HI           0x3C
+#define M98095_03D_DAI3_CLKCFG_LO           0x3D
+#define M98095_03E_DAI3_FORMAT              0x3E
+#define M98095_03F_DAI3_CLOCK               0x3F
+#define M98095_040_DAI3_IOCFG               0x40
+#define M98095_041_DAI3_TDM                 0x41
+#define M98095_042_DAI3_FILTERS             0x42
+#define M98095_043_DAI3_LVL1                0x43
+#define M98095_044_DAI3_LVL2                0x44
+#define M98095_045_CFG_DSP                  0x45
+#define M98095_046_DAC_CTRL1                0x46
+#define M98095_047_DAC_CTRL2                0x47
+#define M98095_048_MIX_DAC_LR               0x48
+#define M98095_049_MIX_DAC_M                0x49
+#define M98095_04A_MIX_ADC_LEFT             0x4A
+#define M98095_04B_MIX_ADC_RIGHT            0x4B
+#define M98095_04C_MIX_HP_LEFT              0x4C
+#define M98095_04D_MIX_HP_RIGHT             0x4D
+#define M98095_04E_CFG_HP                   0x4E
+#define M98095_04F_MIX_RCV                  0x4F
+#define M98095_050_MIX_SPK_LEFT             0x50
+#define M98095_051_MIX_SPK_RIGHT            0x51
+#define M98095_052_MIX_SPK_CFG              0x52
+#define M98095_053_MIX_LINEOUT1             0x53
+#define M98095_054_MIX_LINEOUT2             0x54
+#define M98095_055_MIX_LINEOUT_CFG          0x55
+#define M98095_056_LVL_SIDETONE_DAI12       0x56
+#define M98095_057_LVL_SIDETONE_DAI3        0x57
+#define M98095_058_LVL_DAI1_PLAY            0x58
+#define M98095_059_LVL_DAI1_EQ              0x59
+#define M98095_05A_LVL_DAI2_PLAY            0x5A
+#define M98095_05B_LVL_DAI2_EQ              0x5B
+#define M98095_05C_LVL_DAI3_PLAY            0x5C
+#define M98095_05D_LVL_ADC_L                0x5D
+#define M98095_05E_LVL_ADC_R                0x5E
+#define M98095_05F_LVL_MIC1                 0x5F
+#define M98095_060_LVL_MIC2                 0x60
+#define M98095_061_LVL_LINEIN               0x61
+#define M98095_062_LVL_LINEOUT1             0x62
+#define M98095_063_LVL_LINEOUT2             0x63
+#define M98095_064_LVL_HP_L                 0x64
+#define M98095_065_LVL_HP_R                 0x65
+#define M98095_066_LVL_RCV                  0x66
+#define M98095_067_LVL_SPK_L                0x67
+#define M98095_068_LVL_SPK_R                0x68
+#define M98095_069_MICAGC_CFG               0x69
+#define M98095_06A_MICAGC_THRESH            0x6A
+#define M98095_06B_SPK_NOISEGATE            0x6B
+#define M98095_06C_DAI1_ALC1_TIME           0x6C
+#define M98095_06D_DAI1_ALC1_COMP           0x6D
+#define M98095_06E_DAI1_ALC1_EXPN           0x6E
+#define M98095_06F_DAI1_ALC1_GAIN           0x6F
+#define M98095_070_DAI1_ALC2_TIME           0x70
+#define M98095_071_DAI1_ALC2_COMP           0x71
+#define M98095_072_DAI1_ALC2_EXPN           0x72
+#define M98095_073_DAI1_ALC2_GAIN           0x73
+#define M98095_074_DAI1_ALC3_TIME           0x74
+#define M98095_075_DAI1_ALC3_COMP           0x75
+#define M98095_076_DAI1_ALC3_EXPN           0x76
+#define M98095_077_DAI1_ALC3_GAIN           0x77
+#define M98095_078_DAI2_ALC1_TIME           0x78
+#define M98095_079_DAI2_ALC1_COMP           0x79
+#define M98095_07A_DAI2_ALC1_EXPN           0x7A
+#define M98095_07B_DAI2_ALC1_GAIN           0x7B
+#define M98095_07C_DAI2_ALC2_TIME           0x7C
+#define M98095_07D_DAI2_ALC2_COMP           0x7D
+#define M98095_07E_DAI2_ALC2_EXPN           0x7E
+#define M98095_07F_DAI2_ALC2_GAIN           0x7F
+#define M98095_080_DAI2_ALC3_TIME           0x80
+#define M98095_081_DAI2_ALC3_COMP           0x81
+#define M98095_082_DAI2_ALC3_EXPN           0x82
+#define M98095_083_DAI2_ALC3_GAIN           0x83
+#define M98095_084_HP_NOISE_GATE            0x84
+#define M98095_085_AUX_ADC                  0x85
+#define M98095_086_CFG_LINE                 0x86
+#define M98095_087_CFG_MIC                  0x87
+#define M98095_088_CFG_LEVEL                0x88
+#define M98095_089_JACK_DET_AUTO            0x89
+#define M98095_08A_JACK_DET_MANUAL          0x8A
+#define M98095_08B_JACK_KEYSCAN_DBC         0x8B
+#define M98095_08C_JACK_KEYSCAN_DLY         0x8C
+#define M98095_08D_JACK_KEY_THRESH          0x8D
+#define M98095_08E_JACK_DC_SLEW             0x8E
+#define M98095_08F_JACK_TEST_CFG            0x8F
+#define M98095_090_PWR_EN_IN                0x90
+#define M98095_091_PWR_EN_OUT               0x91
+#define M98095_092_PWR_EN_OUT               0x92
+#define M98095_093_BIAS_CTRL                0x93
+#define M98095_094_PWR_DAC_21               0x94
+#define M98095_095_PWR_DAC_03               0x95
+#define M98095_096_PWR_DAC_CK               0x96
+#define M98095_097_PWR_SYS                  0x97
+
+#define M98095_0FF_REV_ID                   0xFF
+
+#define M98095_REG_CNT                      (0xFF+1)
+#define M98095_REG_MAX_CACHED               0X97
+
+/* MAX98095 Registers Bit Fields */
+
+/* M98095_00F_HOST_CFG */
+	#define M98095_SEG                      (1<<0)
+	#define M98095_XTEN                     (1<<1)
+	#define M98095_MDLLEN                   (1<<2)
+
+/* M98095_027_DAI1_CLKMODE, M98095_031_DAI2_CLKMODE, M98095_03B_DAI3_CLKMODE */
+	#define M98095_CLKMODE_MASK             0xFF
+
+/* M98095_02A_DAI1_FORMAT, M98095_034_DAI2_FORMAT, M98095_03E_DAI3_FORMAT */
+	#define M98095_DAI_MAS                  (1<<7)
+	#define M98095_DAI_WCI                  (1<<6)
+	#define M98095_DAI_BCI                  (1<<5)
+	#define M98095_DAI_DLY                  (1<<4)
+	#define M98095_DAI_TDM                  (1<<2)
+	#define M98095_DAI_FSW                  (1<<1)
+	#define M98095_DAI_WS                   (1<<0)
+
+/* M98095_02B_DAI1_CLOCK, M98095_035_DAI2_CLOCK, M98095_03F_DAI3_CLOCK */
+	#define M98095_DAI_BSEL64               (1<<0)
+	#define M98095_DAI_DOSR_DIV2            (0<<5)
+	#define M98095_DAI_DOSR_DIV4            (1<<5)
+
+/* M98095_02C_DAI1_IOCFG, M98095_036_DAI2_IOCFG, M98095_040_DAI3_IOCFG */
+	#define M98095_S1NORMAL                 (1<<6)
+	#define M98095_S2NORMAL                 (2<<6)
+	#define M98095_S3NORMAL                 (3<<6)
+	#define M98095_SDATA                    (3<<0)
+
+/* M98095_02E_DAI1_FILTERS, M98095_038_DAI2_FILTERS, M98095_042_DAI3_FILTERS */
+	#define M98095_DAI_DHF                  (1<<3)
+
+/* M98095_045_DSP_CFG */
+	#define M98095_DSPNORMAL                (5<<4)
+
+/* M98095_048_MIX_DAC_LR */
+	#define M98095_DAI1L_TO_DACR            (1<<7)
+	#define M98095_DAI1R_TO_DACR            (1<<6)
+	#define M98095_DAI2M_TO_DACR            (1<<5)
+	#define M98095_DAI1L_TO_DACL            (1<<3)
+	#define M98095_DAI1R_TO_DACL            (1<<2)
+	#define M98095_DAI2M_TO_DACL            (1<<1)
+	#define M98095_DAI3M_TO_DACL            (1<<0)
+
+/* M98095_049_MIX_DAC_M */
+	#define M98095_DAI1L_TO_DACM            (1<<3)
+	#define M98095_DAI1R_TO_DACM            (1<<2)
+	#define M98095_DAI2M_TO_DACM            (1<<1)
+	#define M98095_DAI3M_TO_DACM            (1<<0)
+
+/* M98095_04E_MIX_HP_CFG */
+	#define M98095_HPNORMAL                 (3<<4)
+
+/* M98095_05F_LVL_MIC1, M98095_060_LVL_MIC2 */
+	#define M98095_MICPRE_MASK              (3<<5)
+	#define M98095_MICPRE_SHIFT             5
+
+/* M98095_064_LVL_HP_L, M98095_065_LVL_HP_R */
+	#define M98095_HP_MUTE                  (1<<7)
+
+/* M98095_066_LVL_RCV */
+	#define M98095_REC_MUTE                 (1<<7)
+
+/* M98095_067_LVL_SPK_L, M98095_068_LVL_SPK_R */
+	#define M98095_SP_MUTE                  (1<<7)
+
+/* M98095_087_CFG_MIC */
+	#define M98095_MICSEL_MASK              (3<<0)
+	#define M98095_DIGMIC_L                 (1<<2)
+	#define M98095_DIGMIC_R                 (1<<3)
+	#define M98095_DIGMIC2L                 (1<<4)
+	#define M98095_DIGMIC2R                 (1<<5)
+
+/* M98095_088_CFG_LEVEL */
+	#define M98095_VSEN                     (1<<6)
+	#define M98095_ZDEN                     (1<<5)
+	#define M98095_BQ2EN                    (1<<3)
+	#define M98095_BQ1EN                    (1<<2)
+	#define M98095_EQ2EN                    (1<<1)
+	#define M98095_EQ1EN                    (1<<0)
+
+/* M98095_090_PWR_EN_IN */
+	#define M98095_INEN                     (1<<7)
+	#define M98095_MB2EN                    (1<<3)
+	#define M98095_MB1EN                    (1<<2)
+	#define M98095_MBEN                     (3<<2)
+	#define M98095_ADREN                    (1<<1)
+	#define M98095_ADLEN                    (1<<0)
+
+/* M98095_091_PWR_EN_OUT */
+	#define M98095_HPLEN                    (1<<7)
+	#define M98095_HPREN                    (1<<6)
+	#define M98095_SPLEN                    (1<<5)
+	#define M98095_SPREN                    (1<<4)
+	#define M98095_RECEN                    (1<<3)
+	#define M98095_DALEN                    (1<<1)
+	#define M98095_DAREN                    (1<<0)
+
+/* M98095_092_PWR_EN_OUT */
+	#define M98095_SPK_FIXEDSPECTRUM        (0<<4)
+	#define M98095_SPK_SPREADSPECTRUM       (1<<4)
+
+/* M98095_097_PWR_SYS */
+	#define M98095_SHDNRUN                  (1<<7)
+	#define M98095_PERFMODE                 (1<<3)
+	#define M98095_HPPLYBACK                (1<<2)
+	#define M98095_PWRSV8K                  (1<<1)
+	#define M98095_PWRSV                    (1<<0)
+
+#define M98095_COEFS_PER_BAND            5
+
+#define M98095_BYTE1(w) ((w >> 8) & 0xff)
+#define M98095_BYTE0(w) (w & 0xff)
+
+/* Equalizer filter coefficients */
+#define M98095_110_DAI1_EQ_BASE             0x10
+#define M98095_142_DAI2_EQ_BASE             0x42
+
+/* Biquad filter coefficients */
+#define M98095_174_DAI1_BQ_BASE             0x74
+#define M98095_17E_DAI2_BQ_BASE             0x7E
+
+#endif
diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c
index 4d9fb279e146..84ffdebb8a8b 100644
--- a/sound/soc/codecs/sn95031.c
+++ b/sound/soc/codecs/sn95031.c
@@ -827,8 +827,6 @@ EXPORT_SYMBOL_GPL(sn95031_jack_detection);
 /* codec registration */
 static int sn95031_codec_probe(struct snd_soc_codec *codec)
 {
-	int ret;
-
 	pr_debug("codec_probe called\n");
 
 	codec->dapm.bias_level = SND_SOC_BIAS_OFF;
@@ -879,16 +877,7 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec)
 	snd_soc_add_controls(codec, sn95031_snd_controls,
 			     ARRAY_SIZE(sn95031_snd_controls));
 
-	ret = snd_soc_dapm_new_controls(&codec->dapm, sn95031_dapm_widgets,
-				ARRAY_SIZE(sn95031_dapm_widgets));
-	if (ret)
-		pr_err("soc_dapm_new_control failed %d", ret);
-	ret = snd_soc_dapm_add_routes(&codec->dapm, sn95031_audio_map,
-				ARRAY_SIZE(sn95031_audio_map));
-	if (ret)
-		pr_err("soc_dapm_add_routes failed %d", ret);
-
-	return ret;
+	return 0;
 }
 
 static int sn95031_codec_remove(struct snd_soc_codec *codec)
@@ -905,6 +894,10 @@ struct snd_soc_codec_driver sn95031_codec = {
 	.read		= sn95031_read,
 	.write		= sn95031_write,
 	.set_bias_level	= sn95031_set_vaud_bias,
+	.dapm_widgets	= sn95031_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(sn95031_dapm_widgets),
+	.dapm_routes	= sn95031_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(sn95031_audio_map),
 };
 
 static int __devinit sn95031_device_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/spdif_transciever.c b/sound/soc/codecs/spdif_transciever.c
index 4c32b54913ad..6a1a7e705cd7 100644
--- a/sound/soc/codecs/spdif_transciever.c
+++ b/sound/soc/codecs/spdif_transciever.c
@@ -21,7 +21,7 @@
 #include <sound/pcm.h>
 #include <sound/initval.h>
 
-MODULE_LICENSE("GPL");
+#define DRV_NAME "spdif-dit"
 
 #define STUB_RATES	SNDRV_PCM_RATE_8000_96000
 #define STUB_FORMATS	SNDRV_PCM_FMTBIT_S16_LE
@@ -56,7 +56,7 @@ static struct platform_driver spdif_dit_driver = {
 	.probe		= spdif_dit_probe,
 	.remove		= spdif_dit_remove,
 	.driver		= {
-		.name	= "spdif-dit",
+		.name	= DRV_NAME,
 		.owner	= THIS_MODULE,
 	},
 };
@@ -74,3 +74,7 @@ static void __exit dit_exit(void)
 module_init(dit_modinit);
 module_exit(dit_exit);
 
+MODULE_AUTHOR("Steve Chen <schen@mvista.com>");
+MODULE_DESCRIPTION("SPDIF dummy codec driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index b04d28039c16..84f4ad568556 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -32,6 +32,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/spi/spi.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -39,18 +40,25 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/initval.h>
+#include <sound/tlv.h>
 
 #include "ssm2602.h"
 
 #define SSM2602_VERSION "0.1"
 
+enum ssm2602_type {
+	SSM2602,
+	SSM2604,
+};
+
 /* codec private data */
 struct ssm2602_priv {
 	unsigned int sysclk;
 	enum snd_soc_control_type control_type;
-	void *control_data;
 	struct snd_pcm_substream *master_substream;
 	struct snd_pcm_substream *slave_substream;
+
+	enum ssm2602_type type;
 };
 
 /*
@@ -60,60 +68,12 @@ struct ssm2602_priv {
  * There is no point in caching the reset register
  */
 static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = {
-	0x0017, 0x0017, 0x0079, 0x0079,
-	0x0000, 0x0000, 0x0000, 0x000a,
+	0x0097, 0x0097, 0x0079, 0x0079,
+	0x000a, 0x0008, 0x009f, 0x000a,
 	0x0000, 0x0000
 };
 
-/*
- * read ssm2602 register cache
- */
-static inline unsigned int ssm2602_read_reg_cache(struct snd_soc_codec *codec,
-	unsigned int reg)
-{
-	u16 *cache = codec->reg_cache;
-	if (reg == SSM2602_RESET)
-		return 0;
-	if (reg >= SSM2602_CACHEREGNUM)
-		return -1;
-	return cache[reg];
-}
-
-/*
- * write ssm2602 register cache
- */
-static inline void ssm2602_write_reg_cache(struct snd_soc_codec *codec,
-	u16 reg, unsigned int value)
-{
-	u16 *cache = codec->reg_cache;
-	if (reg >= SSM2602_CACHEREGNUM)
-		return;
-	cache[reg] = value;
-}
-
-/*
- * write to the ssm2602 register space
- */
-static int ssm2602_write(struct snd_soc_codec *codec, unsigned int reg,
-	unsigned int value)
-{
-	u8 data[2];
-
-	/* data is
-	 *   D15..D9 ssm2602 register offset
-	 *   D8...D0 register data
-	 */
-	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
-	data[1] = value & 0x00ff;
-
-	ssm2602_write_reg_cache(codec, reg, value);
-	if (codec->hw_write(codec->control_data, data, 2) == 2)
-		return 0;
-	else
-		return -EIO;
-}
-
-#define ssm2602_reset(c)	ssm2602_write(c, SSM2602_RESET, 0)
+#define ssm2602_reset(c)	snd_soc_write(c, SSM2602_RESET, 0)
 
 /*Appending several "None"s just for OSS mixer use*/
 static const char *ssm2602_input_select[] = {
@@ -128,174 +88,187 @@ static const struct soc_enum ssm2602_enum[] = {
 	SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, 4, ssm2602_deemph),
 };
 
-static const struct snd_kcontrol_new ssm2602_snd_controls[] = {
+static const unsigned int ssm260x_outmix_tlv[] = {
+	TLV_DB_RANGE_HEAD(2),
+	0, 47, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
+	48, 127, TLV_DB_SCALE_ITEM(-7400, 100, 0),
+};
 
-SOC_DOUBLE_R("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V,
-	0, 127, 0),
-SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V,
-	7, 1, 0),
+static const DECLARE_TLV_DB_SCALE(ssm260x_inpga_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(ssm260x_sidetone_tlv, -1500, 300, 0);
 
-SOC_DOUBLE_R("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 31, 0),
+static const struct snd_kcontrol_new ssm260x_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 45, 0,
+	ssm260x_inpga_tlv),
 SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1),
 
-SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0),
-SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 8, 1, 0),
-SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1),
-
-SOC_SINGLE("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1),
-
 SOC_SINGLE("ADC High Pass Filter Switch", SSM2602_APDIGI, 0, 1, 1),
 SOC_SINGLE("Store DC Offset Switch", SSM2602_APDIGI, 4, 1, 0),
 
-SOC_ENUM("Capture Source", ssm2602_enum[0]),
-
 SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]),
 };
 
+static const struct snd_kcontrol_new ssm2602_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V,
+	0, 127, 0, ssm260x_outmix_tlv),
+SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V,
+	7, 1, 0),
+SOC_SINGLE_TLV("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1,
+	ssm260x_sidetone_tlv),
+
+SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0),
+SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 8, 1, 0),
+SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1),
+};
+
 /* Output Mixer */
-static const struct snd_kcontrol_new ssm2602_output_mixer_controls[] = {
+static const struct snd_kcontrol_new ssm260x_output_mixer_controls[] = {
 SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0),
-SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0),
 SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0),
+SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0),
 };
 
 /* Input mux */
 static const struct snd_kcontrol_new ssm2602_input_mux_controls =
 SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]);
 
-static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = {
-SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1,
-	&ssm2602_output_mixer_controls[0],
-	ARRAY_SIZE(ssm2602_output_mixer_controls)),
+static const struct snd_soc_dapm_widget ssm260x_dapm_widgets[] = {
 SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1),
+SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1),
+SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("Digital Core Power", SSM2602_ACTIVE, 0, 0, NULL, 0),
+
 SND_SOC_DAPM_OUTPUT("LOUT"),
-SND_SOC_DAPM_OUTPUT("LHPOUT"),
 SND_SOC_DAPM_OUTPUT("ROUT"),
-SND_SOC_DAPM_OUTPUT("RHPOUT"),
-SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1),
+SND_SOC_DAPM_INPUT("RLINEIN"),
+SND_SOC_DAPM_INPUT("LLINEIN"),
+};
+
+static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1,
+	ssm260x_output_mixer_controls,
+	ARRAY_SIZE(ssm260x_output_mixer_controls)),
+
 SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls),
-SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0),
 SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1),
+
+SND_SOC_DAPM_OUTPUT("LHPOUT"),
+SND_SOC_DAPM_OUTPUT("RHPOUT"),
 SND_SOC_DAPM_INPUT("MICIN"),
-SND_SOC_DAPM_INPUT("RLINEIN"),
-SND_SOC_DAPM_INPUT("LLINEIN"),
 };
 
-static const struct snd_soc_dapm_route audio_conn[] = {
-	/* output mixer */
+static const struct snd_soc_dapm_widget ssm2604_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0,
+	ssm260x_output_mixer_controls,
+	ARRAY_SIZE(ssm260x_output_mixer_controls) - 1), /* Last element is the mic */
+};
+
+static const struct snd_soc_dapm_route ssm260x_routes[] = {
+	{"DAC", NULL, "Digital Core Power"},
+	{"ADC", NULL, "Digital Core Power"},
+
 	{"Output Mixer", "Line Bypass Switch", "Line Input"},
 	{"Output Mixer", "HiFi Playback Switch", "DAC"},
+
+	{"ROUT", NULL, "Output Mixer"},
+	{"LOUT", NULL, "Output Mixer"},
+
+	{"Line Input", NULL, "LLINEIN"},
+	{"Line Input", NULL, "RLINEIN"},
+};
+
+static const struct snd_soc_dapm_route ssm2602_routes[] = {
 	{"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
 
-	/* outputs */
 	{"RHPOUT", NULL, "Output Mixer"},
-	{"ROUT", NULL, "Output Mixer"},
 	{"LHPOUT", NULL, "Output Mixer"},
-	{"LOUT", NULL, "Output Mixer"},
 
-	/* input mux */
 	{"Input Mux", "Line", "Line Input"},
 	{"Input Mux", "Mic", "Mic Bias"},
 	{"ADC", NULL, "Input Mux"},
 
-	/* inputs */
-	{"Line Input", NULL, "LLINEIN"},
-	{"Line Input", NULL, "RLINEIN"},
 	{"Mic Bias", NULL, "MICIN"},
 };
 
-static int ssm2602_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, ssm2602_dapm_widgets,
-				  ARRAY_SIZE(ssm2602_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, audio_conn, ARRAY_SIZE(audio_conn));
-
-	return 0;
-}
+static const struct snd_soc_dapm_route ssm2604_routes[] = {
+	{"ADC", NULL, "Line Input"},
+};
 
-struct _coeff_div {
+struct ssm2602_coeff {
 	u32 mclk;
 	u32 rate;
-	u16 fs;
-	u8 sr:4;
-	u8 bosr:1;
-	u8 usb:1;
+	u8 srate;
 };
 
-/* codec mclk clock divider coefficients */
-static const struct _coeff_div coeff_div[] = {
+#define SSM2602_COEFF_SRATE(sr, bosr, usb) (((sr) << 2) | ((bosr) << 1) | (usb))
+
+/* codec mclk clock coefficients */
+static const struct ssm2602_coeff ssm2602_coeff_table[] = {
 	/* 48k */
-	{12288000, 48000, 256, 0x0, 0x0, 0x0},
-	{18432000, 48000, 384, 0x0, 0x1, 0x0},
-	{12000000, 48000, 250, 0x0, 0x0, 0x1},
+	{12288000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x0)},
+	{18432000, 48000, SSM2602_COEFF_SRATE(0x0, 0x1, 0x0)},
+	{12000000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x1)},
 
 	/* 32k */
-	{12288000, 32000, 384, 0x6, 0x0, 0x0},
-	{18432000, 32000, 576, 0x6, 0x1, 0x0},
-	{12000000, 32000, 375, 0x6, 0x0, 0x1},
+	{12288000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x0)},
+	{18432000, 32000, SSM2602_COEFF_SRATE(0x6, 0x1, 0x0)},
+	{12000000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x1)},
 
 	/* 8k */
-	{12288000, 8000, 1536, 0x3, 0x0, 0x0},
-	{18432000, 8000, 2304, 0x3, 0x1, 0x0},
-	{11289600, 8000, 1408, 0xb, 0x0, 0x0},
-	{16934400, 8000, 2112, 0xb, 0x1, 0x0},
-	{12000000, 8000, 1500, 0x3, 0x0, 0x1},
+	{12288000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x0)},
+	{18432000, 8000, SSM2602_COEFF_SRATE(0x3, 0x1, 0x0)},
+	{11289600, 8000, SSM2602_COEFF_SRATE(0xb, 0x0, 0x0)},
+	{16934400, 8000, SSM2602_COEFF_SRATE(0xb, 0x1, 0x0)},
+	{12000000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x1)},
 
 	/* 96k */
-	{12288000, 96000, 128, 0x7, 0x0, 0x0},
-	{18432000, 96000, 192, 0x7, 0x1, 0x0},
-	{12000000, 96000, 125, 0x7, 0x0, 0x1},
+	{12288000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x0)},
+	{18432000, 96000, SSM2602_COEFF_SRATE(0x7, 0x1, 0x0)},
+	{12000000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x1)},
 
 	/* 44.1k */
-	{11289600, 44100, 256, 0x8, 0x0, 0x0},
-	{16934400, 44100, 384, 0x8, 0x1, 0x0},
-	{12000000, 44100, 272, 0x8, 0x1, 0x1},
+	{11289600, 44100, SSM2602_COEFF_SRATE(0x8, 0x0, 0x0)},
+	{16934400, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x0)},
+	{12000000, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x1)},
 
 	/* 88.2k */
-	{11289600, 88200, 128, 0xf, 0x0, 0x0},
-	{16934400, 88200, 192, 0xf, 0x1, 0x0},
-	{12000000, 88200, 136, 0xf, 0x1, 0x1},
+	{11289600, 88200, SSM2602_COEFF_SRATE(0xf, 0x0, 0x0)},
+	{16934400, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x0)},
+	{12000000, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x1)},
 };
 
-static inline int get_coeff(int mclk, int rate)
+static inline int ssm2602_get_coeff(int mclk, int rate)
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
-		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
-			return i;
+	for (i = 0; i < ARRAY_SIZE(ssm2602_coeff_table); i++) {
+		if (ssm2602_coeff_table[i].rate == rate &&
+			ssm2602_coeff_table[i].mclk == mclk)
+			return ssm2602_coeff_table[i].srate;
 	}
-	return i;
+	return -EINVAL;
 }
 
 static int ssm2602_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params,
 	struct snd_soc_dai *dai)
 {
-	u16 srate;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_codec *codec = rtd->codec;
 	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
-	struct i2c_client *i2c = codec->control_data;
-	u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3;
-	int i = get_coeff(ssm2602->sysclk, params_rate(params));
+	u16 iface = snd_soc_read(codec, SSM2602_IFACE) & 0xfff3;
+	int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params));
 
 	if (substream == ssm2602->slave_substream) {
-		dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n");
+		dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n");
 		return 0;
 	}
 
-	/*no match is found*/
-	if (i == ARRAY_SIZE(coeff_div))
-		return -EINVAL;
+	if (srate < 0)
+		return srate;
 
-	srate = (coeff_div[i].sr << 2) |
-		(coeff_div[i].bosr << 1) | coeff_div[i].usb;
-
-	ssm2602_write(codec, SSM2602_ACTIVE, 0);
-	ssm2602_write(codec, SSM2602_SRATE, srate);
+	snd_soc_write(codec, SSM2602_SRATE, srate);
 
 	/* bit size */
 	switch (params_format(params)) {
@@ -311,8 +284,7 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
 		iface |= 0x000c;
 		break;
 	}
-	ssm2602_write(codec, SSM2602_IFACE, iface);
-	ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
+	snd_soc_write(codec, SSM2602_IFACE, iface);
 	return 0;
 }
 
@@ -354,17 +326,6 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream,
-			       struct snd_soc_dai *dai)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
-	/* set active */
-	ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
-
-	return 0;
-}
-
 static void ssm2602_shutdown(struct snd_pcm_substream *substream,
 			     struct snd_soc_dai *dai)
 {
@@ -372,25 +333,22 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream,
 	struct snd_soc_codec *codec = rtd->codec;
 	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 
-	/* deactivate */
-	if (!codec->active)
-		ssm2602_write(codec, SSM2602_ACTIVE, 0);
-
 	if (ssm2602->master_substream == substream)
 		ssm2602->master_substream = ssm2602->slave_substream;
 
 	ssm2602->slave_substream = NULL;
 }
 
+
 static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
 {
 	struct snd_soc_codec *codec = dai->codec;
-	u16 mute_reg = ssm2602_read_reg_cache(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE;
+	u16 mute_reg = snd_soc_read(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE;
 	if (mute)
-		ssm2602_write(codec, SSM2602_APDIGI,
+		snd_soc_write(codec, SSM2602_APDIGI,
 				mute_reg | APDIGI_ENABLE_DAC_MUTE);
 	else
-		ssm2602_write(codec, SSM2602_APDIGI, mute_reg);
+		snd_soc_write(codec, SSM2602_APDIGI, mute_reg);
 	return 0;
 }
 
@@ -466,30 +424,29 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	}
 
 	/* set iface */
-	ssm2602_write(codec, SSM2602_IFACE, iface);
+	snd_soc_write(codec, SSM2602_IFACE, iface);
 	return 0;
 }
 
 static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 {
-	u16 reg = ssm2602_read_reg_cache(codec, SSM2602_PWR) & 0xff7f;
+	u16 reg = snd_soc_read(codec, SSM2602_PWR) & 0xff7f;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		/* vref/mid, osc on, dac unmute */
-		ssm2602_write(codec, SSM2602_PWR, reg);
+		snd_soc_write(codec, SSM2602_PWR, reg);
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		/* everything off except vref/vmid, */
-		ssm2602_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN);
+		snd_soc_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN);
 		break;
 	case SND_SOC_BIAS_OFF:
 		/* everything off, dac mute, inactive */
-		ssm2602_write(codec, SSM2602_ACTIVE, 0);
-		ssm2602_write(codec, SSM2602_PWR, 0xffff);
+		snd_soc_write(codec, SSM2602_PWR, 0xffff);
 		break;
 
 	}
@@ -506,7 +463,6 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
 
 static struct snd_soc_dai_ops ssm2602_dai_ops = {
 	.startup	= ssm2602_startup,
-	.prepare	= ssm2602_pcm_prepare,
 	.hw_params	= ssm2602_hw_params,
 	.shutdown	= ssm2602_shutdown,
 	.digital_mute	= ssm2602_mute,
@@ -539,50 +495,87 @@ static int ssm2602_suspend(struct snd_soc_codec *codec, pm_message_t state)
 
 static int ssm2602_resume(struct snd_soc_codec *codec)
 {
-	int i;
-	u8 data[2];
-	u16 *cache = codec->reg_cache;
-
-	/* Sync reg_cache with the hardware */
-	for (i = 0; i < ARRAY_SIZE(ssm2602_reg); i++) {
-		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
-		data[1] = cache[i] & 0x00ff;
-		codec->hw_write(codec->control_data, data, 2);
-	}
+	snd_soc_cache_sync(codec);
+
 	ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
 	return 0;
 }
 
 static int ssm2602_probe(struct snd_soc_codec *codec)
 {
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	int ret, reg;
+
+	reg = snd_soc_read(codec, SSM2602_LOUT1V);
+	snd_soc_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH);
+	reg = snd_soc_read(codec, SSM2602_ROUT1V);
+	snd_soc_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH);
+
+	ret = snd_soc_add_controls(codec, ssm2602_snd_controls,
+			ARRAY_SIZE(ssm2602_snd_controls));
+	if (ret)
+		return ret;
+
+	ret = snd_soc_dapm_new_controls(dapm, ssm2602_dapm_widgets,
+			ARRAY_SIZE(ssm2602_dapm_widgets));
+	if (ret)
+		return ret;
+
+	return snd_soc_dapm_add_routes(dapm, ssm2602_routes,
+			ARRAY_SIZE(ssm2602_routes));
+}
+
+static int ssm2604_probe(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	int ret;
+
+	ret = snd_soc_dapm_new_controls(dapm, ssm2604_dapm_widgets,
+			ARRAY_SIZE(ssm2604_dapm_widgets));
+	if (ret)
+		return ret;
+
+	return snd_soc_dapm_add_routes(dapm, ssm2604_routes,
+			ARRAY_SIZE(ssm2604_routes));
+}
+
+static int ssm260x_probe(struct snd_soc_codec *codec)
+{
 	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
-	int ret = 0, reg;
+	int ret, reg;
 
 	pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
 
-	codec->control_data = ssm2602->control_data;
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, ssm2602->control_type);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
 
-	ssm2602_reset(codec);
+	ret = ssm2602_reset(codec);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+		return ret;
+	}
 
-	/*power on device*/
-	ssm2602_write(codec, SSM2602_ACTIVE, 0);
 	/* set the update bits */
-	reg = ssm2602_read_reg_cache(codec, SSM2602_LINVOL);
-	ssm2602_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH);
-	reg = ssm2602_read_reg_cache(codec, SSM2602_RINVOL);
-	ssm2602_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH);
-	reg = ssm2602_read_reg_cache(codec, SSM2602_LOUT1V);
-	ssm2602_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH);
-	reg = ssm2602_read_reg_cache(codec, SSM2602_ROUT1V);
-	ssm2602_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH);
+	reg = snd_soc_read(codec, SSM2602_LINVOL);
+	snd_soc_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH);
+	reg = snd_soc_read(codec, SSM2602_RINVOL);
+	snd_soc_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH);
 	/*select Line in as default input*/
-	ssm2602_write(codec, SSM2602_APANA, APANA_SELECT_DAC |
+	snd_soc_write(codec, SSM2602_APANA, APANA_SELECT_DAC |
 			APANA_ENABLE_MIC_BOOST);
-	ssm2602_write(codec, SSM2602_PWR, 0);
 
-	snd_soc_add_controls(codec, ssm2602_snd_controls,
-				ARRAY_SIZE(ssm2602_snd_controls));
-	ssm2602_add_widgets(codec);
+	switch (ssm2602->type) {
+	case SSM2602:
+		ret = ssm2602_probe(codec);
+		break;
+	case SSM2604:
+		ret = ssm2604_probe(codec);
+		break;
+	}
 
 	return ret;
 }
@@ -595,18 +588,61 @@ static int ssm2602_remove(struct snd_soc_codec *codec)
 }
 
 static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
-	.probe =	ssm2602_probe,
+	.probe =	ssm260x_probe,
 	.remove =	ssm2602_remove,
 	.suspend =	ssm2602_suspend,
 	.resume =	ssm2602_resume,
-	.read = ssm2602_read_reg_cache,
-	.write = ssm2602_write,
 	.set_bias_level = ssm2602_set_bias_level,
 	.reg_cache_size = ARRAY_SIZE(ssm2602_reg),
 	.reg_word_size = sizeof(u16),
 	.reg_cache_default = ssm2602_reg,
+
+	.controls = ssm260x_snd_controls,
+	.num_controls = ARRAY_SIZE(ssm260x_snd_controls),
+	.dapm_widgets = ssm260x_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(ssm260x_dapm_widgets),
+	.dapm_routes = ssm260x_routes,
+	.num_dapm_routes = ARRAY_SIZE(ssm260x_routes),
 };
 
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit ssm2602_spi_probe(struct spi_device *spi)
+{
+	struct ssm2602_priv *ssm2602;
+	int ret;
+
+	ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL);
+	if (ssm2602 == NULL)
+		return -ENOMEM;
+
+	spi_set_drvdata(spi, ssm2602);
+	ssm2602->control_type = SND_SOC_SPI;
+	ssm2602->type = SSM2602;
+
+	ret = snd_soc_register_codec(&spi->dev,
+			&soc_codec_dev_ssm2602, &ssm2602_dai, 1);
+	if (ret < 0)
+		kfree(ssm2602);
+	return ret;
+}
+
+static int __devexit ssm2602_spi_remove(struct spi_device *spi)
+{
+	snd_soc_unregister_codec(&spi->dev);
+	kfree(spi_get_drvdata(spi));
+	return 0;
+}
+
+static struct spi_driver ssm2602_spi_driver = {
+	.driver = {
+		.name	= "ssm2602",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ssm2602_spi_probe,
+	.remove		= __devexit_p(ssm2602_spi_remove),
+};
+#endif
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 /*
  * ssm2602 2 wire address is determined by GPIO5
@@ -625,8 +661,8 @@ static int __devinit ssm2602_i2c_probe(struct i2c_client *i2c,
 		return -ENOMEM;
 
 	i2c_set_clientdata(i2c, ssm2602);
-	ssm2602->control_data = i2c;
 	ssm2602->control_type = SND_SOC_I2C;
+	ssm2602->type = id->driver_data;
 
 	ret = snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_ssm2602, &ssm2602_dai, 1);
@@ -643,7 +679,9 @@ static int __devexit ssm2602_i2c_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ssm2602_i2c_id[] = {
-	{ "ssm2602", 0 },
+	{ "ssm2602", SSM2602 },
+	{ "ssm2603", SSM2602 },
+	{ "ssm2604", SSM2604 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
@@ -651,7 +689,7 @@ MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
 /* corgi i2c codec control layer */
 static struct i2c_driver ssm2602_i2c_driver = {
 	.driver = {
-		.name = "ssm2602-codec",
+		.name = "ssm2602",
 		.owner = THIS_MODULE,
 	},
 	.probe = ssm2602_i2c_probe,
@@ -664,25 +702,35 @@ static struct i2c_driver ssm2602_i2c_driver = {
 static int __init ssm2602_modinit(void)
 {
 	int ret = 0;
+
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&ssm2602_spi_driver);
+	if (ret)
+		return ret;
+#endif
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	ret = i2c_add_driver(&ssm2602_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "Failed to register SSM2602 I2C driver: %d\n",
-		       ret);
-	}
+	if (ret)
+		return ret;
 #endif
+
 	return ret;
 }
 module_init(ssm2602_modinit);
 
 static void __exit ssm2602_exit(void)
 {
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&ssm2602_spi_driver);
+#endif
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	i2c_del_driver(&ssm2602_i2c_driver);
 #endif
 }
 module_exit(ssm2602_exit);
 
-MODULE_DESCRIPTION("ASoC ssm2602 driver");
+MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 driver");
 MODULE_AUTHOR("Cliff Cai");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ssm2602.h b/sound/soc/codecs/ssm2602.h
index 42a47d0f8e25..b98c69168036 100644
--- a/sound/soc/codecs/ssm2602.h
+++ b/sound/soc/codecs/ssm2602.h
@@ -117,11 +117,5 @@
 #define SSM2602_CACHEREGNUM 	10
 
 #define SSM2602_SYSCLK	0
-#define SSM2602_DAI		0
-
-struct ssm2602_setup_data {
-	int i2c_bus;
-	unsigned short i2c_address;
-};
 
 #endif
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index 54a30ef0ec8b..33bb52f3f683 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -212,7 +212,7 @@ static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
 	SND_SOC_DAPM_INPUT("MICIN"),
 };
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route tlv320aic23_intercon[] = {
 	/* Output Mixer */
 	{"Output Mixer", "Line Bypass Switch", "Line Input"},
 	{"Output Mixer", "Playback Switch", "DAC"},
@@ -388,18 +388,6 @@ static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk,
 	return 0;
 }
 
-static int tlv320aic23_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets,
-				  ARRAY_SIZE(tlv320aic23_dapm_widgets));
-	/* set up audio path interconnects */
-	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-	return 0;
-}
-
 static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *dai)
@@ -676,7 +664,6 @@ static int tlv320aic23_probe(struct snd_soc_codec *codec)
 
 	snd_soc_add_controls(codec, tlv320aic23_snd_controls,
 				ARRAY_SIZE(tlv320aic23_snd_controls));
-	tlv320aic23_add_widgets(codec);
 
 	return 0;
 }
@@ -698,6 +685,10 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
 	.read = tlv320aic23_read_reg_cache,
 	.write = tlv320aic23_write,
 	.set_bias_level = tlv320aic23_set_bias_level,
+	.dapm_widgets = tlv320aic23_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
+	.dapm_routes = tlv320aic23_intercon,
+	.num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon),
 };
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 6c43c13f0430..c3d96fc8c267 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -157,7 +157,8 @@ static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg,
 static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	unsigned int reg = mc->reg;
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 082e9d51963f..faa5e9fb1471 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -1,7 +1,7 @@
 /*
  * ALSA SoC Texas Instruments TLV320DAC33 codec driver
  *
- * Author:	Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * Copyright:   (C) 2009 Nokia Corporation
  *
@@ -587,6 +587,9 @@ static const struct snd_soc_dapm_widget dac33_dapm_widgets[] = {
 	SND_SOC_DAPM_SUPPLY("Right DAC Power",
 			    DAC33_RDAC_PWR_CTRL, 2, 0, NULL, 0),
 
+	SND_SOC_DAPM_SUPPLY("Codec Power",
+			    DAC33_PWR_CTRL, 4, 0, NULL, 0),
+
 	SND_SOC_DAPM_PRE("Pre Playback", dac33_playback_event),
 	SND_SOC_DAPM_POST("Post Playback", dac33_playback_event),
 };
@@ -619,6 +622,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	/* output */
 	{"LEFT_LO", NULL, "Output Left Amplifier"},
 	{"RIGHT_LO", NULL, "Output Right Amplifier"},
+
+	{"LEFT_LO", NULL, "Codec Power"},
+	{"RIGHT_LO", NULL, "Codec Power"},
 };
 
 static int dac33_add_widgets(struct snd_soc_codec *codec)
@@ -636,13 +642,10 @@ static int dac33_add_widgets(struct snd_soc_codec *codec)
 static int dac33_set_bias_level(struct snd_soc_codec *codec,
 				enum snd_soc_bias_level level)
 {
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 	int ret;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-		if (!dac33->substream)
-			dac33_soft_power(codec, 1);
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		break;
@@ -943,8 +946,8 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
 	/* Write registers 0x08 and 0x09 (MSB, LSB) */
 	dac33_write16(codec, DAC33_INT_OSC_FREQ_RAT_A, oscset);
 
-	/* calib time: 128 is a nice number ;) */
-	dac33_write(codec, DAC33_CALIB_TIME, 128);
+	/* OSC calibration time */
+	dac33_write(codec, DAC33_CALIB_TIME, 96);
 
 	/* adjustment treshold & step */
 	dac33_write(codec, DAC33_INT_OSC_CTRL_B, DAC33_ADJTHRSHLD(2) |
@@ -1655,5 +1658,5 @@ module_exit(dac33_module_exit);
 
 
 MODULE_DESCRIPTION("ASoC TLV320DAC33 codec driver");
-MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@nokia.com>");
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320dac33.h b/sound/soc/codecs/tlv320dac33.h
index 7c318b5da437..ed69670747bf 100644
--- a/sound/soc/codecs/tlv320dac33.h
+++ b/sound/soc/codecs/tlv320dac33.h
@@ -1,7 +1,7 @@
 /*
  * ALSA SoC Texas Instruments TLV320DAC33 codec driver
  *
- * Author:	Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * Copyright:   (C) 2009 Nokia Corporation
  *
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
index 1f1ac8110bef..239e0c461068 100644
--- a/sound/soc/codecs/tpa6130a2.c
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) Nokia Corporation
  *
- * Author: Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -495,7 +495,7 @@ static void __exit tpa6130a2_exit(void)
 	i2c_del_driver(&tpa6130a2_i2c_driver);
 }
 
-MODULE_AUTHOR("Peter Ujfalusi");
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
 MODULE_DESCRIPTION("TPA6130A2 Headphone amplifier driver");
 MODULE_LICENSE("GPL");
 
diff --git a/sound/soc/codecs/tpa6130a2.h b/sound/soc/codecs/tpa6130a2.h
index 5df49c8756b2..417444020ba6 100644
--- a/sound/soc/codecs/tpa6130a2.h
+++ b/sound/soc/codecs/tpa6130a2.h
@@ -3,7 +3,7 @@
  *
  * Copyright (C) Nokia Corporation
  *
- * Author: Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 255901c4460d..4c336636d4f5 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -960,9 +960,9 @@ static DECLARE_TLV_DB_SCALE(mic_amp_tlv, -600, 600, 0);
 
 /*
  * AFMGAIN volume control:
- * from 18 to 24 dB in 6 dB steps
+ * from -18 to 24 dB in 6 dB steps
  */
-static DECLARE_TLV_DB_SCALE(afm_amp_tlv, 1800, 600, 0);
+static DECLARE_TLV_DB_SCALE(afm_amp_tlv, -1800, 600, 0);
 
 /*
  * HSGAIN volume control:
@@ -1049,7 +1049,7 @@ static const struct snd_kcontrol_new twl6040_snd_controls[] = {
 
 	/* AFM gains */
 	SOC_DOUBLE_TLV("Aux FM Volume",
-		TWL6040_REG_LINEGAIN, 0, 4, 0xF, 0, afm_amp_tlv),
+		TWL6040_REG_LINEGAIN, 0, 3, 7, 0, afm_amp_tlv),
 
 	/* Playback gains */
 	SOC_TWL6040_DOUBLE_TLV("Headset Playback Volume",
diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c
new file mode 100644
index 000000000000..14d0716bf009
--- /dev/null
+++ b/sound/soc/codecs/wm1250-ev1.c
@@ -0,0 +1,108 @@
+/*
+ * Driver for the 1250-EV1 audio I/O module
+ *
+ * Copyright 2011 Wolfson Microelectronics plc
+ *
+ *  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/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+static const struct snd_soc_dapm_widget wm1250_ev1_dapm_widgets[] = {
+SND_SOC_DAPM_ADC("ADC", "wm1250-ev1 Capture", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_DAC("DAC", "wm1250-ev1 Playback", SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_INPUT("WM1250 Input"),
+SND_SOC_DAPM_INPUT("WM1250 Output"),
+};
+
+static const struct snd_soc_dapm_route wm1250_ev1_dapm_routes[] = {
+	{ "ADC", NULL, "WM1250 Input" },
+	{ "WM1250 Output", NULL, "DAC" },
+};
+
+static struct snd_soc_dai_driver wm1250_ev1_dai = {
+	.name = "wm1250-ev1",
+	.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,
+	},
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm1250_ev1 = {
+	.dapm_widgets = wm1250_ev1_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm1250_ev1_dapm_widgets),
+	.dapm_routes = wm1250_ev1_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(wm1250_ev1_dapm_routes),
+};
+
+static int __devinit wm1250_ev1_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
+{
+	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm1250_ev1,
+				      &wm1250_ev1_dai, 1);
+}
+
+static int __devexit wm1250_ev1_remove(struct i2c_client *i2c)
+{
+	snd_soc_unregister_codec(&i2c->dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id wm1250_ev1_i2c_id[] = {
+	{ "wm1250-ev1", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm1250_ev1_i2c_id);
+
+static struct i2c_driver wm1250_ev1_i2c_driver = {
+	.driver = {
+		.name = "wm1250-ev1",
+		.owner = THIS_MODULE,
+	},
+	.probe =    wm1250_ev1_probe,
+	.remove =   __devexit_p(wm1250_ev1_remove),
+	.id_table = wm1250_ev1_i2c_id,
+};
+
+static int __init wm1250_ev1_modinit(void)
+{
+	int ret = 0;
+
+	ret = i2c_add_driver(&wm1250_ev1_i2c_driver);
+	if (ret != 0)
+		pr_err("Failed to register WM1250-EV1 I2C driver: %d\n", ret);
+
+	return ret;
+}
+module_init(wm1250_ev1_modinit);
+
+static void __exit wm1250_ev1_exit(void)
+{
+	i2c_del_driver(&wm1250_ev1_i2c_driver);
+}
+module_exit(wm1250_ev1_exit);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM1250-EV1 audio I/O module driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index 97c30382d3ff..a537e4af6ae7 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -77,7 +77,7 @@ SND_SOC_DAPM_OUTPUT("ROUT"),
 SND_SOC_DAPM_OUTPUT("RHPOUT"),
 };
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route wm8711_intercon[] = {
 	/* output mixer */
 	{"Output Mixer", "Line Bypass Switch", "Line Input"},
 	{"Output Mixer", "HiFi Playback Switch", "DAC"},
@@ -89,17 +89,6 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"LOUT", NULL, "Output Mixer"},
 };
 
-static int wm8711_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, wm8711_dapm_widgets,
-				  ARRAY_SIZE(wm8711_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-	return 0;
-}
-
 struct _coeff_div {
 	u32 mclk;
 	u32 rate;
@@ -398,7 +387,6 @@ static int wm8711_probe(struct snd_soc_codec *codec)
 
 	snd_soc_add_controls(codec, wm8711_snd_controls,
 			     ARRAY_SIZE(wm8711_snd_controls));
-	wm8711_add_widgets(codec);
 
 	return ret;
 
@@ -420,6 +408,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8711 = {
 	.reg_cache_size = ARRAY_SIZE(wm8711_reg),
 	.reg_word_size = sizeof(u16),
 	.reg_cache_default = wm8711_reg,
+	.dapm_widgets = wm8711_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8711_dapm_widgets),
+	.dapm_routes = wm8711_intercon,
+	.num_dapm_routes = ARRAY_SIZE(wm8711_intercon),
 };
 
 #if defined(CONFIG_SPI_MASTER)
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index 736b0352d0a7..86d4718d3a76 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -65,22 +65,11 @@ SND_SOC_DAPM_OUTPUT("VOUTL"),
 SND_SOC_DAPM_OUTPUT("VOUTR"),
 };
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route wm8728_intercon[] = {
 	{"VOUTL", NULL, "DAC"},
 	{"VOUTR", NULL, "DAC"},
 };
 
-static int wm8728_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, wm8728_dapm_widgets,
-				  ARRAY_SIZE(wm8728_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-	return 0;
-}
-
 static int wm8728_mute(struct snd_soc_dai *dai, int mute)
 {
 	struct snd_soc_codec *codec = dai->codec;
@@ -255,7 +244,6 @@ static int wm8728_probe(struct snd_soc_codec *codec)
 
 	snd_soc_add_controls(codec, wm8728_snd_controls,
 				ARRAY_SIZE(wm8728_snd_controls));
-	wm8728_add_widgets(codec);
 
 	return ret;
 }
@@ -275,6 +263,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8728 = {
 	.reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults),
 	.reg_word_size = sizeof(u16),
 	.reg_cache_default = wm8728_reg_defaults,
+	.dapm_widgets = wm8728_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8728_dapm_widgets),
+	.dapm_routes = wm8728_intercon,
+	.num_dapm_routes = ARRAY_SIZE(wm8728_intercon),
 };
 
 #if defined(CONFIG_SPI_MASTER)
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 0a67c31b2663..6dec7cee2cb4 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -201,7 +201,7 @@ static int wm8731_check_osc(struct snd_soc_dapm_widget *source,
 	return wm8731->sysclk_type == WM8731_SYSCLK_MCLK;
 }
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route wm8731_intercon[] = {
 	{"DAC", NULL, "OSC", wm8731_check_osc},
 	{"ADC", NULL, "OSC", wm8731_check_osc},
 
@@ -227,17 +227,6 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"Mic Bias", NULL, "MICIN"},
 };
 
-static int wm8731_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, wm8731_dapm_widgets,
-				  ARRAY_SIZE(wm8731_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-	return 0;
-}
-
 struct _coeff_div {
 	u32 mclk;
 	u32 rate;
@@ -599,7 +588,6 @@ static int wm8731_probe(struct snd_soc_codec *codec)
 
 	snd_soc_add_controls(codec, wm8731_snd_controls,
 			     ARRAY_SIZE(wm8731_snd_controls));
-	wm8731_add_widgets(codec);
 
 	/* Regulators will have been enabled by bias management */
 	regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
@@ -636,6 +624,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8731 = {
 	.reg_cache_size = ARRAY_SIZE(wm8731_reg),
 	.reg_word_size = sizeof(u16),
 	.reg_cache_default = wm8731_reg,
+	.dapm_widgets = wm8731_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
+	.dapm_routes = wm8731_intercon,
+	.num_dapm_routes = ARRAY_SIZE(wm8731_intercon),
 };
 
 #if defined(CONFIG_SPI_MASTER)
@@ -667,7 +659,7 @@ static int __devexit wm8731_spi_remove(struct spi_device *spi)
 
 static struct spi_driver wm8731_spi_driver = {
 	.driver = {
-		.name	= "wm8731-codec",
+		.name	= "wm8731",
 		.owner	= THIS_MODULE,
 	},
 	.probe		= wm8731_spi_probe,
@@ -711,7 +703,7 @@ MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id);
 
 static struct i2c_driver wm8731_i2c_driver = {
 	.driver = {
-		.name = "wm8731-codec",
+		.name = "wm8731",
 		.owner = THIS_MODULE,
 	},
 	.probe =    wm8731_i2c_probe,
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 824d1c8c8a35..43e3d760766f 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -382,7 +382,8 @@ static void wm8903_seq_notifier(struct snd_soc_dapm_context *dapm,
 static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct snd_soc_codec *codec = widget->codec;
 	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
 	u16 reg;
@@ -634,6 +635,13 @@ static const struct soc_enum lsidetone_enum =
 static const struct soc_enum rsidetone_enum =
 	SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 0, 3, sidetone_text);
 
+static const char *adcinput_text[] = {
+	"ADC", "DMIC"
+};
+
+static const struct soc_enum adcinput_enum =
+	SOC_ENUM_SINGLE(WM8903_CLOCK_RATE_TEST_4, 9, 2, adcinput_text);
+
 static const char *aif_text[] = {
 	"Left", "Right"
 };
@@ -767,6 +775,9 @@ static const struct snd_kcontrol_new lsidetone_mux =
 static const struct snd_kcontrol_new rsidetone_mux =
 	SOC_DAPM_ENUM("DACR Sidetone Mux", rsidetone_enum);
 
+static const struct snd_kcontrol_new adcinput_mux =
+	SOC_DAPM_ENUM("ADC Input", adcinput_enum);
+
 static const struct snd_kcontrol_new lcapture_mux =
 	SOC_DAPM_ENUM("Left Capture Mux", lcapture_enum);
 
@@ -817,6 +828,7 @@ SND_SOC_DAPM_INPUT("IN2L"),
 SND_SOC_DAPM_INPUT("IN2R"),
 SND_SOC_DAPM_INPUT("IN3L"),
 SND_SOC_DAPM_INPUT("IN3R"),
+SND_SOC_DAPM_INPUT("DMICDAT"),
 
 SND_SOC_DAPM_OUTPUT("HPOUTL"),
 SND_SOC_DAPM_OUTPUT("HPOUTR"),
@@ -842,6 +854,9 @@ SND_SOC_DAPM_MUX("Right Input Mode Mux", SND_SOC_NOPM, 0, 0, &rinput_mode_mux),
 SND_SOC_DAPM_PGA("Left Input PGA", WM8903_POWER_MANAGEMENT_0, 1, 0, NULL, 0),
 SND_SOC_DAPM_PGA("Right Input PGA", WM8903_POWER_MANAGEMENT_0, 0, 0, NULL, 0),
 
+SND_SOC_DAPM_MUX("Left ADC Input", SND_SOC_NOPM, 0, 0, &adcinput_mux),
+SND_SOC_DAPM_MUX("Right ADC Input", SND_SOC_NOPM, 0, 0, &adcinput_mux),
+
 SND_SOC_DAPM_ADC("ADCL", NULL, WM8903_POWER_MANAGEMENT_6, 1, 0),
 SND_SOC_DAPM_ADC("ADCR", NULL, WM8903_POWER_MANAGEMENT_6, 0, 0),
 
@@ -930,7 +945,7 @@ SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8903_CLOCK_RATES_2, 1, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8903_CLOCK_RATES_2, 2, 0, NULL, 0),
 };
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route wm8903_intercon[] = {
 
 	{ "CLK_DSP", NULL, "CLK_SYS" },
 	{ "Mic Bias", NULL, "CLK_SYS" },
@@ -979,6 +994,11 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{ "Left Input PGA", NULL, "Left Input Mode Mux" },
 	{ "Right Input PGA", NULL, "Right Input Mode Mux" },
 
+	{ "Left ADC Input", "ADC", "Left Input PGA" },
+	{ "Left ADC Input", "DMIC", "DMICDAT" },
+	{ "Right ADC Input", "ADC", "Right Input PGA" },
+	{ "Right ADC Input", "DMIC", "DMICDAT" },
+
 	{ "Left Capture Mux", "Left", "ADCL" },
 	{ "Left Capture Mux", "Right", "ADCR" },
 
@@ -988,9 +1008,9 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{ "AIFTXL", NULL, "Left Capture Mux" },
 	{ "AIFTXR", NULL, "Right Capture Mux" },
 
-	{ "ADCL", NULL, "Left Input PGA" },
+	{ "ADCL", NULL, "Left ADC Input" },
 	{ "ADCL", NULL, "CLK_DSP" },
-	{ "ADCR", NULL, "Right Input PGA" },
+	{ "ADCR", NULL, "Right ADC Input" },
 	{ "ADCR", NULL, "CLK_DSP" },
 
 	{ "Left Playback Mux", "Left", "AIFRXL" },
@@ -1087,17 +1107,6 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{ "Right Line Output PGA", NULL, "Charge Pump" },
 };
 
-static int wm8903_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, wm8903_dapm_widgets,
-				  ARRAY_SIZE(wm8903_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-	return 0;
-}
-
 static int wm8903_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 {
@@ -2028,7 +2037,6 @@ static int wm8903_probe(struct snd_soc_codec *codec)
 
 	snd_soc_add_controls(codec, wm8903_snd_controls,
 				ARRAY_SIZE(wm8903_snd_controls));
-	wm8903_add_widgets(codec);
 
 	wm8903_init_gpio(codec);
 
@@ -2054,6 +2062,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8903 = {
 	.reg_cache_default = wm8903_reg_defaults,
 	.volatile_register = wm8903_volatile_register,
 	.seq_notifier = wm8903_seq_notifier,
+	.dapm_widgets = wm8903_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8903_dapm_widgets),
+	.dapm_routes = wm8903_intercon,
+	.num_dapm_routes = ARRAY_SIZE(wm8903_intercon),
 };
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
diff --git a/sound/soc/codecs/wm8915.c b/sound/soc/codecs/wm8915.c
new file mode 100644
index 000000000000..ccc9bd832794
--- /dev/null
+++ b/sound/soc/codecs/wm8915.c
@@ -0,0 +1,2931 @@
+/*
+ * wm8915.c - WM8915 audio codec interface
+ *
+ * Copyright 2011 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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/init.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/gcd.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <trace/events/asoc.h>
+
+#include <sound/wm8915.h>
+#include "wm8915.h"
+
+#define WM8915_AIFS 2
+
+#define HPOUT1L 1
+#define HPOUT1R 2
+#define HPOUT2L 4
+#define HPOUT2R 8
+
+#define WM8915_NUM_SUPPLIES 6
+static const char *wm8915_supply_names[WM8915_NUM_SUPPLIES] = {
+	"DCVDD",
+	"DBVDD",
+	"AVDD1",
+	"AVDD2",
+	"CPVDD",
+	"MICVDD",
+};
+
+struct wm8915_priv {
+	struct snd_soc_codec *codec;
+
+	int ldo1ena;
+
+	int sysclk;
+
+	int fll_src;
+	int fll_fref;
+	int fll_fout;
+
+	struct completion fll_lock;
+
+	u16 dcs_pending;
+	struct completion dcs_done;
+
+	u16 hpout_ena;
+	u16 hpout_pending;
+
+	struct regulator_bulk_data supplies[WM8915_NUM_SUPPLIES];
+	struct notifier_block disable_nb[WM8915_NUM_SUPPLIES];
+
+	struct wm8915_pdata pdata;
+
+	int rx_rate[WM8915_AIFS];
+
+	/* Platform dependant ReTune mobile configuration */
+	int num_retune_mobile_texts;
+	const char **retune_mobile_texts;
+	int retune_mobile_cfg[2];
+	struct soc_enum retune_mobile_enum;
+
+	struct snd_soc_jack *jack;
+	bool detecting;
+	bool jack_mic;
+	wm8915_polarity_fn polarity_cb;
+
+#ifdef CONFIG_GPIOLIB
+	struct gpio_chip gpio_chip;
+#endif
+};
+
+/* We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define WM8915_REGULATOR_EVENT(n) \
+static int wm8915_regulator_event_##n(struct notifier_block *nb, \
+				    unsigned long event, void *data)	\
+{ \
+	struct wm8915_priv *wm8915 = container_of(nb, struct wm8915_priv, \
+						  disable_nb[n]); \
+	if (event & REGULATOR_EVENT_DISABLE) { \
+		wm8915->codec->cache_sync = 1; \
+	} \
+	return 0; \
+}
+
+WM8915_REGULATOR_EVENT(0)
+WM8915_REGULATOR_EVENT(1)
+WM8915_REGULATOR_EVENT(2)
+WM8915_REGULATOR_EVENT(3)
+WM8915_REGULATOR_EVENT(4)
+WM8915_REGULATOR_EVENT(5)
+
+static const u16 wm8915_reg[WM8915_MAX_REGISTER] = {
+	[WM8915_SOFTWARE_RESET] = 0x8915,
+	[WM8915_POWER_MANAGEMENT_7] = 0x10,
+	[WM8915_DAC1_HPOUT1_VOLUME] = 0x88,
+	[WM8915_DAC2_HPOUT2_VOLUME] = 0x88,
+	[WM8915_DAC1_LEFT_VOLUME] = 0x2c0,
+	[WM8915_DAC1_RIGHT_VOLUME] = 0x2c0,
+	[WM8915_DAC2_LEFT_VOLUME] = 0x2c0,
+	[WM8915_DAC2_RIGHT_VOLUME] = 0x2c0,
+	[WM8915_OUTPUT1_LEFT_VOLUME] = 0x80,
+	[WM8915_OUTPUT1_RIGHT_VOLUME] = 0x80,
+	[WM8915_OUTPUT2_LEFT_VOLUME] = 0x80,
+	[WM8915_OUTPUT2_RIGHT_VOLUME] = 0x80,
+	[WM8915_MICBIAS_1] = 0x39,
+	[WM8915_MICBIAS_2] = 0x39,
+	[WM8915_LDO_1] = 0x3,
+	[WM8915_LDO_2] = 0x13,
+	[WM8915_ACCESSORY_DETECT_MODE_1] = 0x4,
+	[WM8915_HEADPHONE_DETECT_1] = 0x20,
+	[WM8915_MIC_DETECT_1] = 0x7600,
+	[WM8915_MIC_DETECT_2] = 0xbf,
+	[WM8915_CHARGE_PUMP_1] = 0x1f25,
+	[WM8915_CHARGE_PUMP_2] = 0xab19,
+	[WM8915_DC_SERVO_5] = 0x2a2a,
+	[WM8915_CONTROL_INTERFACE_1] = 0x8004,
+	[WM8915_CLOCKING_1] = 0x10,
+	[WM8915_AIF_RATE] = 0x83,
+	[WM8915_FLL_CONTROL_4] = 0x5dc0,
+	[WM8915_FLL_CONTROL_5] = 0xc84,
+	[WM8915_FLL_EFS_2] = 0x2,
+	[WM8915_AIF1_TX_LRCLK_1] = 0x80,
+	[WM8915_AIF1_TX_LRCLK_2] = 0x8,
+	[WM8915_AIF1_RX_LRCLK_1] = 0x80,
+	[WM8915_AIF1TX_DATA_CONFIGURATION_1] = 0x1818,
+	[WM8915_AIF1RX_DATA_CONFIGURATION] = 0x1818,
+	[WM8915_AIF1TX_TEST] = 0x7,
+	[WM8915_AIF2_TX_LRCLK_1] = 0x80,
+	[WM8915_AIF2_TX_LRCLK_2] = 0x8,
+	[WM8915_AIF2_RX_LRCLK_1] = 0x80,
+	[WM8915_AIF2TX_DATA_CONFIGURATION_1] = 0x1818,
+	[WM8915_AIF2RX_DATA_CONFIGURATION] = 0x1818,
+	[WM8915_AIF2TX_TEST] = 0x1,
+	[WM8915_DSP1_TX_LEFT_VOLUME] = 0xc0,
+	[WM8915_DSP1_TX_RIGHT_VOLUME] = 0xc0,
+	[WM8915_DSP1_RX_LEFT_VOLUME] = 0xc0,
+	[WM8915_DSP1_RX_RIGHT_VOLUME] = 0xc0,
+	[WM8915_DSP1_TX_FILTERS] = 0x2000,
+	[WM8915_DSP1_RX_FILTERS_1] = 0x200,
+	[WM8915_DSP1_RX_FILTERS_2] = 0x10,
+	[WM8915_DSP1_DRC_1] = 0x98,
+	[WM8915_DSP1_DRC_2] = 0x845,
+	[WM8915_DSP1_RX_EQ_GAINS_1] = 0x6318,
+	[WM8915_DSP1_RX_EQ_GAINS_2] = 0x6300,
+	[WM8915_DSP1_RX_EQ_BAND_1_A] = 0xfca,
+	[WM8915_DSP1_RX_EQ_BAND_1_B] = 0x400,
+	[WM8915_DSP1_RX_EQ_BAND_1_PG] = 0xd8,
+	[WM8915_DSP1_RX_EQ_BAND_2_A] = 0x1eb5,
+	[WM8915_DSP1_RX_EQ_BAND_2_B] = 0xf145,
+	[WM8915_DSP1_RX_EQ_BAND_2_C] = 0xb75,
+	[WM8915_DSP1_RX_EQ_BAND_2_PG] = 0x1c5,
+	[WM8915_DSP1_RX_EQ_BAND_3_A] = 0x1c58,
+	[WM8915_DSP1_RX_EQ_BAND_3_B] = 0xf373,
+	[WM8915_DSP1_RX_EQ_BAND_3_C] = 0xa54,
+	[WM8915_DSP1_RX_EQ_BAND_3_PG] = 0x558,
+	[WM8915_DSP1_RX_EQ_BAND_4_A] = 0x168e,
+	[WM8915_DSP1_RX_EQ_BAND_4_B] = 0xf829,
+	[WM8915_DSP1_RX_EQ_BAND_4_C] = 0x7ad,
+	[WM8915_DSP1_RX_EQ_BAND_4_PG] = 0x1103,
+	[WM8915_DSP1_RX_EQ_BAND_5_A] = 0x564,
+	[WM8915_DSP1_RX_EQ_BAND_5_B] = 0x559,
+	[WM8915_DSP1_RX_EQ_BAND_5_PG] = 0x4000,
+	[WM8915_DSP2_TX_LEFT_VOLUME] = 0xc0,
+	[WM8915_DSP2_TX_RIGHT_VOLUME] = 0xc0,
+	[WM8915_DSP2_RX_LEFT_VOLUME] = 0xc0,
+	[WM8915_DSP2_RX_RIGHT_VOLUME] = 0xc0,
+	[WM8915_DSP2_TX_FILTERS] = 0x2000,
+	[WM8915_DSP2_RX_FILTERS_1] = 0x200,
+	[WM8915_DSP2_RX_FILTERS_2] = 0x10,
+	[WM8915_DSP2_DRC_1] = 0x98,
+	[WM8915_DSP2_DRC_2] = 0x845,
+	[WM8915_DSP2_RX_EQ_GAINS_1] = 0x6318,
+	[WM8915_DSP2_RX_EQ_GAINS_2] = 0x6300,
+	[WM8915_DSP2_RX_EQ_BAND_1_A] = 0xfca,
+	[WM8915_DSP2_RX_EQ_BAND_1_B] = 0x400,
+	[WM8915_DSP2_RX_EQ_BAND_1_PG] = 0xd8,
+	[WM8915_DSP2_RX_EQ_BAND_2_A] = 0x1eb5,
+	[WM8915_DSP2_RX_EQ_BAND_2_B] = 0xf145,
+	[WM8915_DSP2_RX_EQ_BAND_2_C] = 0xb75,
+	[WM8915_DSP2_RX_EQ_BAND_2_PG] = 0x1c5,
+	[WM8915_DSP2_RX_EQ_BAND_3_A] = 0x1c58,
+	[WM8915_DSP2_RX_EQ_BAND_3_B] = 0xf373,
+	[WM8915_DSP2_RX_EQ_BAND_3_C] = 0xa54,
+	[WM8915_DSP2_RX_EQ_BAND_3_PG] = 0x558,
+	[WM8915_DSP2_RX_EQ_BAND_4_A] = 0x168e,
+	[WM8915_DSP2_RX_EQ_BAND_4_B] = 0xf829,
+	[WM8915_DSP2_RX_EQ_BAND_4_C] = 0x7ad,
+	[WM8915_DSP2_RX_EQ_BAND_4_PG] = 0x1103,
+	[WM8915_DSP2_RX_EQ_BAND_5_A] = 0x564,
+	[WM8915_DSP2_RX_EQ_BAND_5_B] = 0x559,
+	[WM8915_DSP2_RX_EQ_BAND_5_PG] = 0x4000,
+	[WM8915_OVERSAMPLING] = 0xd,
+	[WM8915_SIDETONE] = 0x1040,
+	[WM8915_GPIO_1] = 0xa101,
+	[WM8915_GPIO_2] = 0xa101,
+	[WM8915_GPIO_3] = 0xa101,
+	[WM8915_GPIO_4] = 0xa101,
+	[WM8915_GPIO_5] = 0xa101,
+	[WM8915_PULL_CONTROL_2] = 0x140,
+	[WM8915_INTERRUPT_STATUS_1_MASK] = 0x1f,
+	[WM8915_INTERRUPT_STATUS_2_MASK] = 0x1ecf,
+	[WM8915_RIGHT_PDM_SPEAKER] = 0x1,
+	[WM8915_PDM_SPEAKER_MUTE_SEQUENCE] = 0x69,
+	[WM8915_PDM_SPEAKER_VOLUME] = 0x66,
+	[WM8915_WRITE_SEQUENCER_0] = 0x1,
+	[WM8915_WRITE_SEQUENCER_1] = 0x1,
+	[WM8915_WRITE_SEQUENCER_3] = 0x6,
+	[WM8915_WRITE_SEQUENCER_4] = 0x40,
+	[WM8915_WRITE_SEQUENCER_5] = 0x1,
+	[WM8915_WRITE_SEQUENCER_6] = 0xf,
+	[WM8915_WRITE_SEQUENCER_7] = 0x6,
+	[WM8915_WRITE_SEQUENCER_8] = 0x1,
+	[WM8915_WRITE_SEQUENCER_9] = 0x3,
+	[WM8915_WRITE_SEQUENCER_10] = 0x104,
+	[WM8915_WRITE_SEQUENCER_12] = 0x60,
+	[WM8915_WRITE_SEQUENCER_13] = 0x11,
+	[WM8915_WRITE_SEQUENCER_14] = 0x401,
+	[WM8915_WRITE_SEQUENCER_16] = 0x50,
+	[WM8915_WRITE_SEQUENCER_17] = 0x3,
+	[WM8915_WRITE_SEQUENCER_18] = 0x100,
+	[WM8915_WRITE_SEQUENCER_20] = 0x51,
+	[WM8915_WRITE_SEQUENCER_21] = 0x3,
+	[WM8915_WRITE_SEQUENCER_22] = 0x104,
+	[WM8915_WRITE_SEQUENCER_23] = 0xa,
+	[WM8915_WRITE_SEQUENCER_24] = 0x60,
+	[WM8915_WRITE_SEQUENCER_25] = 0x3b,
+	[WM8915_WRITE_SEQUENCER_26] = 0x502,
+	[WM8915_WRITE_SEQUENCER_27] = 0x100,
+	[WM8915_WRITE_SEQUENCER_28] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_32] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_36] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_40] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_44] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_48] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_52] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_56] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_60] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_64] = 0x1,
+	[WM8915_WRITE_SEQUENCER_65] = 0x1,
+	[WM8915_WRITE_SEQUENCER_67] = 0x6,
+	[WM8915_WRITE_SEQUENCER_68] = 0x40,
+	[WM8915_WRITE_SEQUENCER_69] = 0x1,
+	[WM8915_WRITE_SEQUENCER_70] = 0xf,
+	[WM8915_WRITE_SEQUENCER_71] = 0x6,
+	[WM8915_WRITE_SEQUENCER_72] = 0x1,
+	[WM8915_WRITE_SEQUENCER_73] = 0x3,
+	[WM8915_WRITE_SEQUENCER_74] = 0x104,
+	[WM8915_WRITE_SEQUENCER_76] = 0x60,
+	[WM8915_WRITE_SEQUENCER_77] = 0x11,
+	[WM8915_WRITE_SEQUENCER_78] = 0x401,
+	[WM8915_WRITE_SEQUENCER_80] = 0x50,
+	[WM8915_WRITE_SEQUENCER_81] = 0x3,
+	[WM8915_WRITE_SEQUENCER_82] = 0x100,
+	[WM8915_WRITE_SEQUENCER_84] = 0x60,
+	[WM8915_WRITE_SEQUENCER_85] = 0x3b,
+	[WM8915_WRITE_SEQUENCER_86] = 0x502,
+	[WM8915_WRITE_SEQUENCER_87] = 0x100,
+	[WM8915_WRITE_SEQUENCER_88] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_92] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_96] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_100] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_104] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_108] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_112] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_116] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_120] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_124] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_128] = 0x1,
+	[WM8915_WRITE_SEQUENCER_129] = 0x1,
+	[WM8915_WRITE_SEQUENCER_131] = 0x6,
+	[WM8915_WRITE_SEQUENCER_132] = 0x40,
+	[WM8915_WRITE_SEQUENCER_133] = 0x1,
+	[WM8915_WRITE_SEQUENCER_134] = 0xf,
+	[WM8915_WRITE_SEQUENCER_135] = 0x6,
+	[WM8915_WRITE_SEQUENCER_136] = 0x1,
+	[WM8915_WRITE_SEQUENCER_137] = 0x3,
+	[WM8915_WRITE_SEQUENCER_138] = 0x106,
+	[WM8915_WRITE_SEQUENCER_140] = 0x61,
+	[WM8915_WRITE_SEQUENCER_141] = 0x11,
+	[WM8915_WRITE_SEQUENCER_142] = 0x401,
+	[WM8915_WRITE_SEQUENCER_144] = 0x50,
+	[WM8915_WRITE_SEQUENCER_145] = 0x3,
+	[WM8915_WRITE_SEQUENCER_146] = 0x102,
+	[WM8915_WRITE_SEQUENCER_148] = 0x51,
+	[WM8915_WRITE_SEQUENCER_149] = 0x3,
+	[WM8915_WRITE_SEQUENCER_150] = 0x106,
+	[WM8915_WRITE_SEQUENCER_151] = 0xa,
+	[WM8915_WRITE_SEQUENCER_152] = 0x61,
+	[WM8915_WRITE_SEQUENCER_153] = 0x3b,
+	[WM8915_WRITE_SEQUENCER_154] = 0x502,
+	[WM8915_WRITE_SEQUENCER_155] = 0x100,
+	[WM8915_WRITE_SEQUENCER_156] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_160] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_164] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_168] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_172] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_176] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_180] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_184] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_188] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_192] = 0x1,
+	[WM8915_WRITE_SEQUENCER_193] = 0x1,
+	[WM8915_WRITE_SEQUENCER_195] = 0x6,
+	[WM8915_WRITE_SEQUENCER_196] = 0x40,
+	[WM8915_WRITE_SEQUENCER_197] = 0x1,
+	[WM8915_WRITE_SEQUENCER_198] = 0xf,
+	[WM8915_WRITE_SEQUENCER_199] = 0x6,
+	[WM8915_WRITE_SEQUENCER_200] = 0x1,
+	[WM8915_WRITE_SEQUENCER_201] = 0x3,
+	[WM8915_WRITE_SEQUENCER_202] = 0x106,
+	[WM8915_WRITE_SEQUENCER_204] = 0x61,
+	[WM8915_WRITE_SEQUENCER_205] = 0x11,
+	[WM8915_WRITE_SEQUENCER_206] = 0x401,
+	[WM8915_WRITE_SEQUENCER_208] = 0x50,
+	[WM8915_WRITE_SEQUENCER_209] = 0x3,
+	[WM8915_WRITE_SEQUENCER_210] = 0x102,
+	[WM8915_WRITE_SEQUENCER_212] = 0x61,
+	[WM8915_WRITE_SEQUENCER_213] = 0x3b,
+	[WM8915_WRITE_SEQUENCER_214] = 0x502,
+	[WM8915_WRITE_SEQUENCER_215] = 0x100,
+	[WM8915_WRITE_SEQUENCER_216] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_220] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_224] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_228] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_232] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_236] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_240] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_244] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_248] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_252] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_256] = 0x60,
+	[WM8915_WRITE_SEQUENCER_258] = 0x601,
+	[WM8915_WRITE_SEQUENCER_260] = 0x50,
+	[WM8915_WRITE_SEQUENCER_262] = 0x100,
+	[WM8915_WRITE_SEQUENCER_264] = 0x1,
+	[WM8915_WRITE_SEQUENCER_266] = 0x104,
+	[WM8915_WRITE_SEQUENCER_267] = 0x100,
+	[WM8915_WRITE_SEQUENCER_268] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_272] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_276] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_280] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_284] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_288] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_292] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_296] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_300] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_304] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_308] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_312] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_316] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_320] = 0x61,
+	[WM8915_WRITE_SEQUENCER_322] = 0x601,
+	[WM8915_WRITE_SEQUENCER_324] = 0x50,
+	[WM8915_WRITE_SEQUENCER_326] = 0x102,
+	[WM8915_WRITE_SEQUENCER_328] = 0x1,
+	[WM8915_WRITE_SEQUENCER_330] = 0x106,
+	[WM8915_WRITE_SEQUENCER_331] = 0x100,
+	[WM8915_WRITE_SEQUENCER_332] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_336] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_340] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_344] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_348] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_352] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_356] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_360] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_364] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_368] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_372] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_376] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_380] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_384] = 0x60,
+	[WM8915_WRITE_SEQUENCER_386] = 0x601,
+	[WM8915_WRITE_SEQUENCER_388] = 0x61,
+	[WM8915_WRITE_SEQUENCER_390] = 0x601,
+	[WM8915_WRITE_SEQUENCER_392] = 0x50,
+	[WM8915_WRITE_SEQUENCER_394] = 0x300,
+	[WM8915_WRITE_SEQUENCER_396] = 0x1,
+	[WM8915_WRITE_SEQUENCER_398] = 0x304,
+	[WM8915_WRITE_SEQUENCER_400] = 0x40,
+	[WM8915_WRITE_SEQUENCER_402] = 0xf,
+	[WM8915_WRITE_SEQUENCER_404] = 0x1,
+	[WM8915_WRITE_SEQUENCER_407] = 0x100,
+};
+
+static const DECLARE_TLV_DB_SCALE(inpga_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 150, 0);
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(out_digital_tlv, -1200, 150, 0);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -900, 75, 0);
+static const DECLARE_TLV_DB_SCALE(spk_tlv, -900, 150, 0);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+
+static const char *sidetone_hpf_text[] = {
+	"2.9kHz", "1.5kHz", "735Hz", "403Hz", "196Hz", "98Hz", "49Hz"
+};
+
+static const struct soc_enum sidetone_hpf =
+	SOC_ENUM_SINGLE(WM8915_SIDETONE, 7, 6, sidetone_hpf_text);
+
+static const char *hpf_mode_text[] = {
+	"HiFi", "Custom", "Voice"
+};
+
+static const struct soc_enum dsp1tx_hpf_mode =
+	SOC_ENUM_SINGLE(WM8915_DSP1_TX_FILTERS, 3, 3, hpf_mode_text);
+
+static const struct soc_enum dsp2tx_hpf_mode =
+	SOC_ENUM_SINGLE(WM8915_DSP2_TX_FILTERS, 3, 3, hpf_mode_text);
+
+static const char *hpf_cutoff_text[] = {
+	"50Hz", "75Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
+};
+
+static const struct soc_enum dsp1tx_hpf_cutoff =
+	SOC_ENUM_SINGLE(WM8915_DSP1_TX_FILTERS, 0, 7, hpf_cutoff_text);
+
+static const struct soc_enum dsp2tx_hpf_cutoff =
+	SOC_ENUM_SINGLE(WM8915_DSP2_TX_FILTERS, 0, 7, hpf_cutoff_text);
+
+static void wm8915_set_retune_mobile(struct snd_soc_codec *codec, int block)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	struct wm8915_pdata *pdata = &wm8915->pdata;
+	int base, best, best_val, save, i, cfg, iface;
+
+	if (!wm8915->num_retune_mobile_texts)
+		return;
+
+	switch (block) {
+	case 0:
+		base = WM8915_DSP1_RX_EQ_GAINS_1;
+		if (snd_soc_read(codec, WM8915_POWER_MANAGEMENT_8) &
+		    WM8915_DSP1RX_SRC)
+			iface = 1;
+		else
+			iface = 0;
+		break;
+	case 1:
+		base = WM8915_DSP1_RX_EQ_GAINS_2;
+		if (snd_soc_read(codec, WM8915_POWER_MANAGEMENT_8) &
+		    WM8915_DSP2RX_SRC)
+			iface = 1;
+		else
+			iface = 0;
+		break;
+	default:
+		return;
+	}
+
+	/* Find the version of the currently selected configuration
+	 * with the nearest sample rate. */
+	cfg = wm8915->retune_mobile_cfg[block];
+	best = 0;
+	best_val = INT_MAX;
+	for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+		if (strcmp(pdata->retune_mobile_cfgs[i].name,
+			   wm8915->retune_mobile_texts[cfg]) == 0 &&
+		    abs(pdata->retune_mobile_cfgs[i].rate
+			- wm8915->rx_rate[iface]) < best_val) {
+			best = i;
+			best_val = abs(pdata->retune_mobile_cfgs[i].rate
+				       - wm8915->rx_rate[iface]);
+		}
+	}
+
+	dev_dbg(codec->dev, "ReTune Mobile %d %s/%dHz for %dHz sample rate\n",
+		block,
+		pdata->retune_mobile_cfgs[best].name,
+		pdata->retune_mobile_cfgs[best].rate,
+		wm8915->rx_rate[iface]);
+
+	/* The EQ will be disabled while reconfiguring it, remember the
+	 * current configuration. 
+	 */
+	save = snd_soc_read(codec, base);
+	save &= WM8915_DSP1RX_EQ_ENA;
+
+	for (i = 0; i < ARRAY_SIZE(pdata->retune_mobile_cfgs[best].regs); i++)
+		snd_soc_update_bits(codec, base + i, 0xffff,
+				    pdata->retune_mobile_cfgs[best].regs[i]);
+
+	snd_soc_update_bits(codec, base, WM8915_DSP1RX_EQ_ENA, save);
+}
+
+/* Icky as hell but saves code duplication */
+static int wm8915_get_retune_mobile_block(const char *name)
+{
+	if (strcmp(name, "DSP1 EQ Mode") == 0)
+		return 0;
+	if (strcmp(name, "DSP2 EQ Mode") == 0)
+		return 1;
+	return -EINVAL;
+}
+
+static int wm8915_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	struct wm8915_pdata *pdata = &wm8915->pdata;
+	int block = wm8915_get_retune_mobile_block(kcontrol->id.name);
+	int value = ucontrol->value.integer.value[0];
+
+	if (block < 0)
+		return block;
+
+	if (value >= pdata->num_retune_mobile_cfgs)
+		return -EINVAL;
+
+	wm8915->retune_mobile_cfg[block] = value;
+
+	wm8915_set_retune_mobile(codec, block);
+
+	return 0;
+}
+
+static int wm8915_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	int block = wm8915_get_retune_mobile_block(kcontrol->id.name);
+
+	ucontrol->value.enumerated.item[0] = wm8915->retune_mobile_cfg[block];
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new wm8915_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Capture Volume", WM8915_LEFT_LINE_INPUT_VOLUME,
+		 WM8915_RIGHT_LINE_INPUT_VOLUME, 0, 31, 0, inpga_tlv),
+SOC_DOUBLE_R("Capture ZC Switch", WM8915_LEFT_LINE_INPUT_VOLUME,
+	     WM8915_RIGHT_LINE_INPUT_VOLUME, 5, 1, 0),
+
+SOC_DOUBLE_TLV("DAC1 Sidetone Volume", WM8915_DAC1_MIXER_VOLUMES,
+	       0, 5, 24, 0, sidetone_tlv),
+SOC_DOUBLE_TLV("DAC2 Sidetone Volume", WM8915_DAC2_MIXER_VOLUMES,
+	       0, 5, 24, 0, sidetone_tlv),
+SOC_SINGLE("Sidetone LPF Switch", WM8915_SIDETONE, 12, 1, 0),
+SOC_ENUM("Sidetone HPF Cut-off", sidetone_hpf),
+SOC_SINGLE("Sidetone HPF Switch", WM8915_SIDETONE, 6, 1, 0),
+
+SOC_DOUBLE_R_TLV("DSP1 Capture Volume", WM8915_DSP1_TX_LEFT_VOLUME,
+		 WM8915_DSP1_TX_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("DSP2 Capture Volume", WM8915_DSP2_TX_LEFT_VOLUME,
+		 WM8915_DSP2_TX_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+
+SOC_SINGLE("DSP1 Capture Notch Filter Switch", WM8915_DSP1_TX_FILTERS,
+	   13, 1, 0),
+SOC_DOUBLE("DSP1 Capture HPF Switch", WM8915_DSP1_TX_FILTERS, 12, 11, 1, 0),
+SOC_ENUM("DSP1 Capture HPF Mode", dsp1tx_hpf_mode),
+SOC_ENUM("DSP1 Capture HPF Cutoff", dsp1tx_hpf_cutoff),
+
+SOC_SINGLE("DSP2 Capture Notch Filter Switch", WM8915_DSP2_TX_FILTERS,
+	   13, 1, 0),
+SOC_DOUBLE("DSP2 Capture HPF Switch", WM8915_DSP2_TX_FILTERS, 12, 11, 1, 0),
+SOC_ENUM("DSP2 Capture HPF Mode", dsp2tx_hpf_mode),
+SOC_ENUM("DSP2 Capture HPF Cutoff", dsp2tx_hpf_cutoff),
+
+SOC_DOUBLE_R_TLV("DSP1 Playback Volume", WM8915_DSP1_RX_LEFT_VOLUME,
+		 WM8915_DSP1_RX_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_SINGLE("DSP1 Playback Switch", WM8915_DSP1_RX_FILTERS_1, 9, 1, 1),
+
+SOC_DOUBLE_R_TLV("DSP2 Playback Volume", WM8915_DSP2_RX_LEFT_VOLUME,
+		 WM8915_DSP2_RX_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_SINGLE("DSP2 Playback Switch", WM8915_DSP2_RX_FILTERS_1, 9, 1, 1),
+
+SOC_DOUBLE_R_TLV("DAC1 Volume", WM8915_DAC1_LEFT_VOLUME,
+		 WM8915_DAC1_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_DOUBLE_R("DAC1 Switch", WM8915_DAC1_LEFT_VOLUME,
+	     WM8915_DAC1_RIGHT_VOLUME, 9, 1, 1),
+
+SOC_DOUBLE_R_TLV("DAC2 Volume", WM8915_DAC2_LEFT_VOLUME,
+		 WM8915_DAC2_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_DOUBLE_R("DAC2 Switch", WM8915_DAC2_LEFT_VOLUME,
+	     WM8915_DAC2_RIGHT_VOLUME, 9, 1, 1),
+
+SOC_SINGLE("Speaker High Performance Switch", WM8915_OVERSAMPLING, 3, 1, 0),
+SOC_SINGLE("DMIC High Performance Switch", WM8915_OVERSAMPLING, 2, 1, 0),
+SOC_SINGLE("ADC High Performance Switch", WM8915_OVERSAMPLING, 1, 1, 0),
+SOC_SINGLE("DAC High Performance Switch", WM8915_OVERSAMPLING, 0, 1, 0),
+
+SOC_SINGLE("DAC Soft Mute Switch", WM8915_DAC_SOFTMUTE, 1, 1, 0),
+SOC_SINGLE("DAC Slow Soft Mute Switch", WM8915_DAC_SOFTMUTE, 0, 1, 0),
+
+SOC_DOUBLE_TLV("Digital Output 1 Volume", WM8915_DAC1_HPOUT1_VOLUME, 0, 4,
+	       8, 0, out_digital_tlv),
+SOC_DOUBLE_TLV("Digital Output 2 Volume", WM8915_DAC2_HPOUT2_VOLUME, 0, 4,
+	       8, 0, out_digital_tlv),
+
+SOC_DOUBLE_R_TLV("Output 1 Volume", WM8915_OUTPUT1_LEFT_VOLUME,
+		 WM8915_OUTPUT1_RIGHT_VOLUME, 0, 12, 0, out_tlv),
+SOC_DOUBLE_R("Output 1 ZC Switch",  WM8915_OUTPUT1_LEFT_VOLUME,
+	     WM8915_OUTPUT1_RIGHT_VOLUME, 7, 1, 0),
+
+SOC_DOUBLE_R_TLV("Output 2 Volume", WM8915_OUTPUT2_LEFT_VOLUME,
+		 WM8915_OUTPUT2_RIGHT_VOLUME, 0, 12, 0, out_tlv),
+SOC_DOUBLE_R("Output 2 ZC Switch",  WM8915_OUTPUT2_LEFT_VOLUME,
+	     WM8915_OUTPUT2_RIGHT_VOLUME, 7, 1, 0),
+
+SOC_DOUBLE_TLV("Speaker Volume", WM8915_PDM_SPEAKER_VOLUME, 0, 4, 8, 0,
+	       spk_tlv),
+SOC_DOUBLE_R("Speaker Switch", WM8915_LEFT_PDM_SPEAKER,
+	     WM8915_RIGHT_PDM_SPEAKER, 3, 1, 1),
+SOC_DOUBLE_R("Speaker ZC Switch", WM8915_LEFT_PDM_SPEAKER,
+	     WM8915_RIGHT_PDM_SPEAKER, 2, 1, 0),
+
+SOC_SINGLE("DSP1 EQ Switch", WM8915_DSP1_RX_EQ_GAINS_1, 0, 1, 0),
+SOC_SINGLE("DSP2 EQ Switch", WM8915_DSP2_RX_EQ_GAINS_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8915_eq_controls[] = {
+SOC_SINGLE_TLV("DSP1 EQ B1 Volume", WM8915_DSP1_RX_EQ_GAINS_1, 11, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B2 Volume", WM8915_DSP1_RX_EQ_GAINS_1, 6, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B3 Volume", WM8915_DSP1_RX_EQ_GAINS_1, 1, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B4 Volume", WM8915_DSP1_RX_EQ_GAINS_2, 11, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B5 Volume", WM8915_DSP1_RX_EQ_GAINS_2, 6, 31, 0,
+	       eq_tlv),
+
+SOC_SINGLE_TLV("DSP2 EQ B1 Volume", WM8915_DSP2_RX_EQ_GAINS_1, 11, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B2 Volume", WM8915_DSP2_RX_EQ_GAINS_1, 6, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B3 Volume", WM8915_DSP2_RX_EQ_GAINS_1, 1, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B4 Volume", WM8915_DSP2_RX_EQ_GAINS_2, 11, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B5 Volume", WM8915_DSP2_RX_EQ_GAINS_2, 6, 31, 0,
+	       eq_tlv),
+};
+
+static int cp_event(struct snd_soc_dapm_widget *w,
+		    struct snd_kcontrol *kcontrol, int event)
+{
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		msleep(5);
+		break;
+	default:
+		BUG();
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rmv_short_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(w->codec);
+
+	/* Record which outputs we enabled */
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMD:
+		wm8915->hpout_pending &= ~w->shift;
+		break;
+	case SND_SOC_DAPM_PRE_PMU:
+		wm8915->hpout_pending |= w->shift;
+		break;
+	default:
+		BUG();
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void wait_for_dc_servo(struct snd_soc_codec *codec, u16 mask)
+{
+	struct i2c_client *i2c = to_i2c_client(codec->dev);
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	int i, ret;
+	unsigned long timeout = 200;
+
+	snd_soc_write(codec, WM8915_DC_SERVO_2, mask);
+
+	/* Use the interrupt if possible */
+	do {
+		if (i2c->irq) {
+			timeout = wait_for_completion_timeout(&wm8915->dcs_done,
+							      msecs_to_jiffies(200));
+			if (timeout == 0)
+				dev_err(codec->dev, "DC servo timed out\n");
+
+		} else {
+			msleep(1);
+			if (--i) {
+				timeout = 0;
+				break;
+			}
+		}
+
+		ret = snd_soc_read(codec, WM8915_DC_SERVO_2);
+		dev_dbg(codec->dev, "DC servo state: %x\n", ret);
+	} while (ret & mask);
+
+	if (timeout == 0)
+		dev_err(codec->dev, "DC servo timed out for %x\n", mask);
+	else
+		dev_dbg(codec->dev, "DC servo complete for %x\n", mask);
+}
+
+static void wm8915_seq_notifier(struct snd_soc_dapm_context *dapm,
+				enum snd_soc_dapm_type event, int subseq)
+{
+	struct snd_soc_codec *codec = container_of(dapm,
+						   struct snd_soc_codec, dapm);
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	u16 val, mask;
+
+	/* Complete any pending DC servo starts */
+	if (wm8915->dcs_pending) {
+		dev_dbg(codec->dev, "Starting DC servo for %x\n",
+			wm8915->dcs_pending);
+
+		/* Trigger a startup sequence */
+		wait_for_dc_servo(codec, wm8915->dcs_pending
+				         << WM8915_DCS_TRIG_STARTUP_0_SHIFT);
+
+		wm8915->dcs_pending = 0;
+	}
+
+	if (wm8915->hpout_pending != wm8915->hpout_ena) {
+		dev_dbg(codec->dev, "Applying RMV_SHORTs %x->%x\n",
+			wm8915->hpout_ena, wm8915->hpout_pending);
+
+		val = 0;
+		mask = 0;
+		if (wm8915->hpout_pending & HPOUT1L) {
+			val |= WM8915_HPOUT1L_RMV_SHORT;
+			mask |= WM8915_HPOUT1L_RMV_SHORT;
+		} else {
+			mask |= WM8915_HPOUT1L_RMV_SHORT |
+				WM8915_HPOUT1L_OUTP |
+				WM8915_HPOUT1L_DLY;
+		}
+
+		if (wm8915->hpout_pending & HPOUT1R) {
+			val |= WM8915_HPOUT1R_RMV_SHORT;
+			mask |= WM8915_HPOUT1R_RMV_SHORT;
+		} else {
+			mask |= WM8915_HPOUT1R_RMV_SHORT |
+				WM8915_HPOUT1R_OUTP |
+				WM8915_HPOUT1R_DLY;
+		}
+
+		snd_soc_update_bits(codec, WM8915_ANALOGUE_HP_1, mask, val);
+
+		val = 0;
+		mask = 0;
+		if (wm8915->hpout_pending & HPOUT2L) {
+			val |= WM8915_HPOUT2L_RMV_SHORT;
+			mask |= WM8915_HPOUT2L_RMV_SHORT;
+		} else {
+			mask |= WM8915_HPOUT2L_RMV_SHORT |
+				WM8915_HPOUT2L_OUTP |
+				WM8915_HPOUT2L_DLY;
+		}
+
+		if (wm8915->hpout_pending & HPOUT2R) {
+			val |= WM8915_HPOUT2R_RMV_SHORT;
+			mask |= WM8915_HPOUT2R_RMV_SHORT;
+		} else {
+			mask |= WM8915_HPOUT2R_RMV_SHORT |
+				WM8915_HPOUT2R_OUTP |
+				WM8915_HPOUT2R_DLY;
+		}
+
+		snd_soc_update_bits(codec, WM8915_ANALOGUE_HP_2, mask, val);
+
+		wm8915->hpout_ena = wm8915->hpout_pending;
+	}
+}
+
+static int dcs_start(struct snd_soc_dapm_widget *w,
+		     struct snd_kcontrol *kcontrol, int event)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(w->codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		wm8915->dcs_pending |= 1 << w->shift;
+		break;
+	default:
+		BUG();
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const char *sidetone_text[] = {
+	"IN1", "IN2",
+};
+
+static const struct soc_enum left_sidetone_enum =
+	SOC_ENUM_SINGLE(WM8915_SIDETONE, 0, 2, sidetone_text);
+
+static const struct snd_kcontrol_new left_sidetone =
+	SOC_DAPM_ENUM("Left Sidetone", left_sidetone_enum);
+
+static const struct soc_enum right_sidetone_enum =
+	SOC_ENUM_SINGLE(WM8915_SIDETONE, 1, 2, sidetone_text);
+
+static const struct snd_kcontrol_new right_sidetone =
+	SOC_DAPM_ENUM("Right Sidetone", right_sidetone_enum);
+
+static const char *spk_text[] = {
+	"DAC1L", "DAC1R", "DAC2L", "DAC2R"
+};
+
+static const struct soc_enum spkl_enum =
+	SOC_ENUM_SINGLE(WM8915_LEFT_PDM_SPEAKER, 0, 4, spk_text);
+
+static const struct snd_kcontrol_new spkl_mux =
+	SOC_DAPM_ENUM("SPKL", spkl_enum);
+
+static const struct soc_enum spkr_enum =
+	SOC_ENUM_SINGLE(WM8915_RIGHT_PDM_SPEAKER, 0, 4, spk_text);
+
+static const struct snd_kcontrol_new spkr_mux =
+	SOC_DAPM_ENUM("SPKR", spkr_enum);
+
+static const char *dsp1rx_text[] = {
+	"AIF1", "AIF2"
+};
+
+static const struct soc_enum dsp1rx_enum =
+	SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_8, 0, 2, dsp1rx_text);
+
+static const struct snd_kcontrol_new dsp1rx =
+	SOC_DAPM_ENUM("DSP1RX", dsp1rx_enum);
+
+static const char *dsp2rx_text[] = {
+	 "AIF2", "AIF1"
+};
+
+static const struct soc_enum dsp2rx_enum =
+	SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_8, 4, 2, dsp2rx_text);
+
+static const struct snd_kcontrol_new dsp2rx =
+	SOC_DAPM_ENUM("DSP2RX", dsp2rx_enum);
+
+static const char *aif2tx_text[] = {
+	"DSP2", "DSP1", "AIF1"
+};
+
+static const struct soc_enum aif2tx_enum =
+	SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_8, 6, 3, aif2tx_text);
+
+static const struct snd_kcontrol_new aif2tx =
+	SOC_DAPM_ENUM("AIF2TX", aif2tx_enum);
+
+static const char *inmux_text[] = {
+	"ADC", "DMIC1", "DMIC2"
+};
+
+static const struct soc_enum in1_enum =
+	SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_7, 0, 3, inmux_text);
+
+static const struct snd_kcontrol_new in1_mux =
+	SOC_DAPM_ENUM("IN1 Mux", in1_enum);
+
+static const struct soc_enum in2_enum =
+	SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_7, 4, 3, inmux_text);
+
+static const struct snd_kcontrol_new in2_mux =
+	SOC_DAPM_ENUM("IN2 Mux", in2_enum);
+
+static const struct snd_kcontrol_new dac2r_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING,
+		5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING,
+		4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac2l_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC2_LEFT_MIXER_ROUTING,
+		5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC2_LEFT_MIXER_ROUTING,
+		4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC2_LEFT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC2_LEFT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac1r_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING,
+		5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING,
+		4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac1l_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC1_LEFT_MIXER_ROUTING,
+		5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC1_LEFT_MIXER_ROUTING,
+		4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC1_LEFT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC1_LEFT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp1txl[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP1_TX_LEFT_MIXER_ROUTING,
+		1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP1_TX_LEFT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp1txr[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP1_TX_RIGHT_MIXER_ROUTING,
+		1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP1_TX_RIGHT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp2txl[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP2_TX_LEFT_MIXER_ROUTING,
+		1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP2_TX_LEFT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp2txr[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP2_TX_RIGHT_MIXER_ROUTING,
+		1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP2_TX_RIGHT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+
+static const struct snd_soc_dapm_widget wm8915_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1LN"),
+SND_SOC_DAPM_INPUT("IN1LP"),
+SND_SOC_DAPM_INPUT("IN1RN"),
+SND_SOC_DAPM_INPUT("IN1RP"),
+
+SND_SOC_DAPM_INPUT("IN2LN"),
+SND_SOC_DAPM_INPUT("IN2LP"),
+SND_SOC_DAPM_INPUT("IN2RN"),
+SND_SOC_DAPM_INPUT("IN2RP"),
+
+SND_SOC_DAPM_INPUT("DMIC1DAT"),
+SND_SOC_DAPM_INPUT("DMIC2DAT"),
+
+SND_SOC_DAPM_SUPPLY_S("SYSCLK", 1, WM8915_AIF_CLOCKING_1, 0, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY_S("SYSDSPCLK", 2, WM8915_CLOCKING_1, 1, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY_S("AIFCLK", 2, WM8915_CLOCKING_1, 2, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY_S("Charge Pump", 2, WM8915_CHARGE_PUMP_1, 15, 0, cp_event,
+		      SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_SUPPLY("LDO2", WM8915_POWER_MANAGEMENT_2, 1, 0, NULL, 0),
+SND_SOC_DAPM_MICBIAS("MICB2", WM8915_POWER_MANAGEMENT_1, 9, 0),
+SND_SOC_DAPM_MICBIAS("MICB1", WM8915_POWER_MANAGEMENT_1, 8, 0),
+
+SND_SOC_DAPM_PGA("IN1L PGA", WM8915_POWER_MANAGEMENT_2, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN1R PGA", WM8915_POWER_MANAGEMENT_2, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("IN1L Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
+SND_SOC_DAPM_MUX("IN1R Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
+SND_SOC_DAPM_MUX("IN2L Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
+SND_SOC_DAPM_MUX("IN2R Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
+
+SND_SOC_DAPM_PGA("IN1L", WM8915_POWER_MANAGEMENT_7, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN1R", WM8915_POWER_MANAGEMENT_7, 3, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN2L", WM8915_POWER_MANAGEMENT_7, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN2R", WM8915_POWER_MANAGEMENT_7, 7, 0, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("DMIC2", WM8915_POWER_MANAGEMENT_7, 9, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("DMIC1", WM8915_POWER_MANAGEMENT_7, 8, 0, NULL, 0),
+
+SND_SOC_DAPM_ADC("DMIC2L", NULL, WM8915_POWER_MANAGEMENT_3, 5, 0),
+SND_SOC_DAPM_ADC("DMIC2R", NULL, WM8915_POWER_MANAGEMENT_3, 4, 0),
+SND_SOC_DAPM_ADC("DMIC1L", NULL, WM8915_POWER_MANAGEMENT_3, 3, 0),
+SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8915_POWER_MANAGEMENT_3, 2, 0),
+
+SND_SOC_DAPM_ADC("ADCL", NULL, WM8915_POWER_MANAGEMENT_3, 1, 0),
+SND_SOC_DAPM_ADC("ADCR", NULL, WM8915_POWER_MANAGEMENT_3, 0, 0),
+
+SND_SOC_DAPM_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &left_sidetone),
+SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &right_sidetone),
+
+SND_SOC_DAPM_AIF_IN("DSP2RXL", NULL, 0, WM8915_POWER_MANAGEMENT_3, 11, 0),
+SND_SOC_DAPM_AIF_IN("DSP2RXR", NULL, 1, WM8915_POWER_MANAGEMENT_3, 10, 0),
+SND_SOC_DAPM_AIF_IN("DSP1RXL", NULL, 0, WM8915_POWER_MANAGEMENT_3, 9, 0),
+SND_SOC_DAPM_AIF_IN("DSP1RXR", NULL, 1, WM8915_POWER_MANAGEMENT_3, 8, 0),
+
+SND_SOC_DAPM_MIXER("DSP2TXL", WM8915_POWER_MANAGEMENT_5, 11, 0,
+		   dsp2txl, ARRAY_SIZE(dsp2txl)),
+SND_SOC_DAPM_MIXER("DSP2TXR", WM8915_POWER_MANAGEMENT_5, 10, 0,
+		   dsp2txr, ARRAY_SIZE(dsp2txr)),
+SND_SOC_DAPM_MIXER("DSP1TXL", WM8915_POWER_MANAGEMENT_5, 9, 0,
+		   dsp1txl, ARRAY_SIZE(dsp1txl)),
+SND_SOC_DAPM_MIXER("DSP1TXR", WM8915_POWER_MANAGEMENT_5, 8, 0,
+		   dsp1txr, ARRAY_SIZE(dsp1txr)),
+
+SND_SOC_DAPM_MIXER("DAC2L Mixer", SND_SOC_NOPM, 0, 0,
+		   dac2l_mix, ARRAY_SIZE(dac2l_mix)),
+SND_SOC_DAPM_MIXER("DAC2R Mixer", SND_SOC_NOPM, 0, 0,
+		   dac2r_mix, ARRAY_SIZE(dac2r_mix)),
+SND_SOC_DAPM_MIXER("DAC1L Mixer", SND_SOC_NOPM, 0, 0,
+		   dac1l_mix, ARRAY_SIZE(dac1l_mix)),
+SND_SOC_DAPM_MIXER("DAC1R Mixer", SND_SOC_NOPM, 0, 0,
+		   dac1r_mix, ARRAY_SIZE(dac1r_mix)),
+
+SND_SOC_DAPM_DAC("DAC2L", NULL, WM8915_POWER_MANAGEMENT_5, 3, 0),
+SND_SOC_DAPM_DAC("DAC2R", NULL, WM8915_POWER_MANAGEMENT_5, 2, 0),
+SND_SOC_DAPM_DAC("DAC1L", NULL, WM8915_POWER_MANAGEMENT_5, 1, 0),
+SND_SOC_DAPM_DAC("DAC1R", NULL, WM8915_POWER_MANAGEMENT_5, 0, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2RX1", "AIF2 Playback", 1,
+		    WM8915_POWER_MANAGEMENT_4, 9, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX0", "AIF2 Playback", 2,
+		    WM8915_POWER_MANAGEMENT_4, 8, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2TX1", "AIF2 Capture", 1,
+		    WM8915_POWER_MANAGEMENT_6, 9, 0),
+SND_SOC_DAPM_AIF_IN("AIF2TX0", "AIF2 Capture", 2,
+		    WM8915_POWER_MANAGEMENT_6, 8, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX5", "AIF1 Playback", 5,
+		    WM8915_POWER_MANAGEMENT_4, 5, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", "AIF1 Playback", 4,
+		    WM8915_POWER_MANAGEMENT_4, 4, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", "AIF1 Playback", 3,
+		    WM8915_POWER_MANAGEMENT_4, 3, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", "AIF1 Playback", 2,
+		    WM8915_POWER_MANAGEMENT_4, 2, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX1", "AIF1 Playback", 1,
+		    WM8915_POWER_MANAGEMENT_4, 1, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX0", "AIF1 Playback", 0,
+		    WM8915_POWER_MANAGEMENT_4, 0, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", "AIF1 Capture", 5,
+		     WM8915_POWER_MANAGEMENT_6, 5, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", "AIF1 Capture", 4,
+		     WM8915_POWER_MANAGEMENT_6, 4, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", "AIF1 Capture", 3,
+		     WM8915_POWER_MANAGEMENT_6, 3, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", "AIF1 Capture", 2,
+		     WM8915_POWER_MANAGEMENT_6, 2, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", "AIF1 Capture", 1,
+		     WM8915_POWER_MANAGEMENT_6, 1, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX0", "AIF1 Capture", 0,
+		     WM8915_POWER_MANAGEMENT_6, 0, 0),
+
+/* We route as stereo pairs so define some dummy widgets to squash
+ * things down for now.  RXA = 0,1, RXB = 2,3 and so on */
+SND_SOC_DAPM_PGA("AIF1RXA", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("AIF1RXB", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("AIF1RXC", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("AIF2RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("DSP2TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("DSP1RX", SND_SOC_NOPM, 0, 0, &dsp1rx),
+SND_SOC_DAPM_MUX("DSP2RX", SND_SOC_NOPM, 0, 0, &dsp2rx),
+SND_SOC_DAPM_MUX("AIF2TX", SND_SOC_NOPM, 0, 0, &aif2tx),
+
+SND_SOC_DAPM_MUX("SPKL", SND_SOC_NOPM, 0, 0, &spkl_mux),
+SND_SOC_DAPM_MUX("SPKR", SND_SOC_NOPM, 0, 0, &spkr_mux),
+SND_SOC_DAPM_PGA("SPKL PGA", WM8915_LEFT_PDM_SPEAKER, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SPKR PGA", WM8915_RIGHT_PDM_SPEAKER, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("HPOUT2L PGA", 0, WM8915_POWER_MANAGEMENT_1, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2L_DLY", 1, WM8915_ANALOGUE_HP_2, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2L_DCS", 2, WM8915_DC_SERVO_1, 2, 0, dcs_start,
+		   SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT2L_OUTP", 3, WM8915_ANALOGUE_HP_2, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2L_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT2L, 0,
+		   rmv_short_event,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_PGA_S("HPOUT2R PGA", 0, WM8915_POWER_MANAGEMENT_1, 6, 0,NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2R_DLY", 1, WM8915_ANALOGUE_HP_2, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2R_DCS", 2, WM8915_DC_SERVO_1, 3, 0, dcs_start,
+		   SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT2R_OUTP", 3, WM8915_ANALOGUE_HP_2, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2R_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT2R, 0,
+		   rmv_short_event,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_PGA_S("HPOUT1L PGA", 0, WM8915_POWER_MANAGEMENT_1, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1L_DLY", 1, WM8915_ANALOGUE_HP_1, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1L_DCS", 2, WM8915_DC_SERVO_1, 0, 0, dcs_start,
+		   SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT1L_OUTP", 3, WM8915_ANALOGUE_HP_1, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1L_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT1L, 0,
+		   rmv_short_event,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_PGA_S("HPOUT1R PGA", 0, WM8915_POWER_MANAGEMENT_1, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1R_DLY", 1, WM8915_ANALOGUE_HP_1, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1R_DCS", 2, WM8915_DC_SERVO_1, 1, 0, dcs_start,
+		   SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT1R_OUTP", 3, WM8915_ANALOGUE_HP_1, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1R_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT1R, 0,
+		   rmv_short_event,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_OUTPUT("HPOUT1L"),
+SND_SOC_DAPM_OUTPUT("HPOUT1R"),
+SND_SOC_DAPM_OUTPUT("HPOUT2L"),
+SND_SOC_DAPM_OUTPUT("HPOUT2R"),
+SND_SOC_DAPM_OUTPUT("SPKDAT"),
+};
+
+static const struct snd_soc_dapm_route wm8915_dapm_routes[] = {
+	{ "AIFCLK", NULL, "SYSCLK" },
+	{ "SYSDSPCLK", NULL, "SYSCLK" },
+	{ "Charge Pump", NULL, "SYSCLK" },
+
+	{ "MICB1", NULL, "LDO2" },
+	{ "MICB2", NULL, "LDO2" },
+
+	{ "IN1L PGA", NULL, "IN2LN" },
+	{ "IN1L PGA", NULL, "IN2LP" },
+	{ "IN1L PGA", NULL, "IN1LN" },
+	{ "IN1L PGA", NULL, "IN1LP" },
+
+	{ "IN1R PGA", NULL, "IN2RN" },
+	{ "IN1R PGA", NULL, "IN2RP" },
+	{ "IN1R PGA", NULL, "IN1RN" },
+	{ "IN1R PGA", NULL, "IN1RP" },
+
+	{ "ADCL", NULL, "IN1L PGA" },
+
+	{ "ADCR", NULL, "IN1R PGA" },
+
+	{ "DMIC1L", NULL, "DMIC1DAT" },
+	{ "DMIC1R", NULL, "DMIC1DAT" },
+	{ "DMIC2L", NULL, "DMIC2DAT" },
+	{ "DMIC2R", NULL, "DMIC2DAT" },
+
+	{ "DMIC2L", NULL, "DMIC2" },
+	{ "DMIC2R", NULL, "DMIC2" },
+	{ "DMIC1L", NULL, "DMIC1" },
+	{ "DMIC1R", NULL, "DMIC1" },
+
+	{ "IN1L Mux", "ADC", "ADCL" },
+	{ "IN1L Mux", "DMIC1", "DMIC1L" },
+	{ "IN1L Mux", "DMIC2", "DMIC2L" },
+
+	{ "IN1R Mux", "ADC", "ADCR" },
+	{ "IN1R Mux", "DMIC1", "DMIC1R" },
+	{ "IN1R Mux", "DMIC2", "DMIC2R" },
+
+	{ "IN2L Mux", "ADC", "ADCL" },
+	{ "IN2L Mux", "DMIC1", "DMIC1L" },
+	{ "IN2L Mux", "DMIC2", "DMIC2L" },
+
+	{ "IN2R Mux", "ADC", "ADCR" },
+	{ "IN2R Mux", "DMIC1", "DMIC1R" },
+	{ "IN2R Mux", "DMIC2", "DMIC2R" },
+
+	{ "Left Sidetone", "IN1", "IN1L Mux" },
+	{ "Left Sidetone", "IN2", "IN2L Mux" },
+
+	{ "Right Sidetone", "IN1", "IN1R Mux" },
+	{ "Right Sidetone", "IN2", "IN2R Mux" },
+
+	{ "DSP1TXL", "IN1 Switch", "IN1L Mux" },
+	{ "DSP1TXR", "IN1 Switch", "IN1R Mux" },
+
+	{ "DSP2TXL", "IN1 Switch", "IN2L Mux" },
+	{ "DSP2TXR", "IN1 Switch", "IN2R Mux" },
+
+	{ "AIF1TX0", NULL, "DSP1TXL" },
+	{ "AIF1TX1", NULL, "DSP1TXR" },
+	{ "AIF1TX2", NULL, "DSP2TXL" },
+	{ "AIF1TX3", NULL, "DSP2TXR" },
+	{ "AIF1TX4", NULL, "AIF2RX0" },
+	{ "AIF1TX5", NULL, "AIF2RX1" },
+
+	{ "AIF1RX0", NULL, "AIFCLK" },
+	{ "AIF1RX1", NULL, "AIFCLK" },
+	{ "AIF1RX2", NULL, "AIFCLK" },
+	{ "AIF1RX3", NULL, "AIFCLK" },
+	{ "AIF1RX4", NULL, "AIFCLK" },
+	{ "AIF1RX5", NULL, "AIFCLK" },
+
+	{ "AIF2RX0", NULL, "AIFCLK" },
+	{ "AIF2RX1", NULL, "AIFCLK" },
+
+	{ "DSP1RXL", NULL, "SYSDSPCLK" },
+	{ "DSP1RXR", NULL, "SYSDSPCLK" },
+	{ "DSP2RXL", NULL, "SYSDSPCLK" },
+	{ "DSP2RXR", NULL, "SYSDSPCLK" },
+	{ "DSP1TXL", NULL, "SYSDSPCLK" },
+	{ "DSP1TXR", NULL, "SYSDSPCLK" },
+	{ "DSP2TXL", NULL, "SYSDSPCLK" },
+	{ "DSP2TXR", NULL, "SYSDSPCLK" },
+
+	{ "AIF1RXA", NULL, "AIF1RX0" },
+	{ "AIF1RXA", NULL, "AIF1RX1" },
+	{ "AIF1RXB", NULL, "AIF1RX2" },
+	{ "AIF1RXB", NULL, "AIF1RX3" },
+	{ "AIF1RXC", NULL, "AIF1RX4" },
+	{ "AIF1RXC", NULL, "AIF1RX5" },
+
+	{ "AIF2RX", NULL, "AIF2RX0" },
+	{ "AIF2RX", NULL, "AIF2RX1" },
+
+	{ "AIF2TX", "DSP2", "DSP2TX" },
+	{ "AIF2TX", "DSP1", "DSP1RX" },
+	{ "AIF2TX", "AIF1", "AIF1RXC" },
+
+	{ "DSP1RXL", NULL, "DSP1RX" },
+	{ "DSP1RXR", NULL, "DSP1RX" },
+	{ "DSP2RXL", NULL, "DSP2RX" },
+	{ "DSP2RXR", NULL, "DSP2RX" },
+
+	{ "DSP2TX", NULL, "DSP2TXL" },
+	{ "DSP2TX", NULL, "DSP2TXR" },
+
+	{ "DSP1RX", "AIF1", "AIF1RXA" },
+	{ "DSP1RX", "AIF2", "AIF2RX" },
+
+	{ "DSP2RX", "AIF1", "AIF1RXB" },
+	{ "DSP2RX", "AIF2", "AIF2RX" },
+
+	{ "DAC2L Mixer", "DSP2 Switch", "DSP2RXL" },
+	{ "DAC2L Mixer", "DSP1 Switch", "DSP1RXL" },
+	{ "DAC2L Mixer", "Right Sidetone Switch", "Right Sidetone" },
+	{ "DAC2L Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+	{ "DAC2R Mixer", "DSP2 Switch", "DSP2RXR" },
+	{ "DAC2R Mixer", "DSP1 Switch", "DSP1RXR" },
+	{ "DAC2R Mixer", "Right Sidetone Switch", "Right Sidetone" },
+	{ "DAC2R Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+	{ "DAC1L Mixer", "DSP2 Switch", "DSP2RXL" },
+	{ "DAC1L Mixer", "DSP1 Switch", "DSP1RXL" },
+	{ "DAC1L Mixer", "Right Sidetone Switch", "Right Sidetone" },
+	{ "DAC1L Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+	{ "DAC1R Mixer", "DSP2 Switch", "DSP2RXR" },
+	{ "DAC1R Mixer", "DSP1 Switch", "DSP1RXR" },
+	{ "DAC1R Mixer", "Right Sidetone Switch", "Right Sidetone" },
+	{ "DAC1R Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+	{ "DAC1L", NULL, "DAC1L Mixer" },
+	{ "DAC1R", NULL, "DAC1R Mixer" },
+	{ "DAC2L", NULL, "DAC2L Mixer" },
+	{ "DAC2R", NULL, "DAC2R Mixer" },
+
+	{ "HPOUT2L PGA", NULL, "Charge Pump" },
+	{ "HPOUT2L PGA", NULL, "DAC2L" },
+	{ "HPOUT2L_DLY", NULL, "HPOUT2L PGA" },
+	{ "HPOUT2L_DCS", NULL, "HPOUT2L_DLY" },
+	{ "HPOUT2L_OUTP", NULL, "HPOUT2L_DCS" },
+	{ "HPOUT2L_RMV_SHORT", NULL, "HPOUT2L_OUTP" },
+
+	{ "HPOUT2R PGA", NULL, "Charge Pump" },
+	{ "HPOUT2R PGA", NULL, "DAC2R" },
+	{ "HPOUT2R_DLY", NULL, "HPOUT2R PGA" },
+	{ "HPOUT2R_DCS", NULL, "HPOUT2R_DLY" },
+	{ "HPOUT2R_OUTP", NULL, "HPOUT2R_DCS" },
+	{ "HPOUT2R_RMV_SHORT", NULL, "HPOUT2R_OUTP" },
+
+	{ "HPOUT1L PGA", NULL, "Charge Pump" },
+	{ "HPOUT1L PGA", NULL, "DAC1L" },
+	{ "HPOUT1L_DLY", NULL, "HPOUT1L PGA" },
+	{ "HPOUT1L_DCS", NULL, "HPOUT1L_DLY" },
+	{ "HPOUT1L_OUTP", NULL, "HPOUT1L_DCS" },
+	{ "HPOUT1L_RMV_SHORT", NULL, "HPOUT1L_OUTP" },
+
+	{ "HPOUT1R PGA", NULL, "Charge Pump" },
+	{ "HPOUT1R PGA", NULL, "DAC1R" },
+	{ "HPOUT1R_DLY", NULL, "HPOUT1R PGA" },
+	{ "HPOUT1R_DCS", NULL, "HPOUT1R_DLY" },
+	{ "HPOUT1R_OUTP", NULL, "HPOUT1R_DCS" },
+	{ "HPOUT1R_RMV_SHORT", NULL, "HPOUT1R_OUTP" },
+
+	{ "HPOUT2L", NULL, "HPOUT2L_RMV_SHORT" },
+	{ "HPOUT2R", NULL, "HPOUT2R_RMV_SHORT" },
+	{ "HPOUT1L", NULL, "HPOUT1L_RMV_SHORT" },
+	{ "HPOUT1R", NULL, "HPOUT1R_RMV_SHORT" },
+
+	{ "SPKL", "DAC1L", "DAC1L" },
+	{ "SPKL", "DAC1R", "DAC1R" },
+	{ "SPKL", "DAC2L", "DAC2L" },
+	{ "SPKL", "DAC2R", "DAC2R" },
+
+	{ "SPKR", "DAC1L", "DAC1L" },
+	{ "SPKR", "DAC1R", "DAC1R" },
+	{ "SPKR", "DAC2L", "DAC2L" },
+	{ "SPKR", "DAC2R", "DAC2R" },
+
+	{ "SPKL PGA", NULL, "SPKL" },
+	{ "SPKR PGA", NULL, "SPKR" },
+
+	{ "SPKDAT", NULL, "SPKL PGA" },
+	{ "SPKDAT", NULL, "SPKR PGA" },
+};
+
+static int wm8915_readable_register(struct snd_soc_codec *codec,
+				    unsigned int reg)
+{
+	/* Due to the sparseness of the register map the compiler
+	 * output from an explicit switch statement ends up being much
+	 * more efficient than a table.
+	 */
+	switch (reg) {
+	case WM8915_SOFTWARE_RESET:
+	case WM8915_POWER_MANAGEMENT_1:
+	case WM8915_POWER_MANAGEMENT_2:
+	case WM8915_POWER_MANAGEMENT_3:
+	case WM8915_POWER_MANAGEMENT_4:
+	case WM8915_POWER_MANAGEMENT_5:
+	case WM8915_POWER_MANAGEMENT_6:
+	case WM8915_POWER_MANAGEMENT_7:
+	case WM8915_POWER_MANAGEMENT_8:
+	case WM8915_LEFT_LINE_INPUT_VOLUME:
+	case WM8915_RIGHT_LINE_INPUT_VOLUME:
+	case WM8915_LINE_INPUT_CONTROL:
+	case WM8915_DAC1_HPOUT1_VOLUME:
+	case WM8915_DAC2_HPOUT2_VOLUME:
+	case WM8915_DAC1_LEFT_VOLUME:
+	case WM8915_DAC1_RIGHT_VOLUME:
+	case WM8915_DAC2_LEFT_VOLUME:
+	case WM8915_DAC2_RIGHT_VOLUME:
+	case WM8915_OUTPUT1_LEFT_VOLUME:
+	case WM8915_OUTPUT1_RIGHT_VOLUME:
+	case WM8915_OUTPUT2_LEFT_VOLUME:
+	case WM8915_OUTPUT2_RIGHT_VOLUME:
+	case WM8915_MICBIAS_1:
+	case WM8915_MICBIAS_2:
+	case WM8915_LDO_1:
+	case WM8915_LDO_2:
+	case WM8915_ACCESSORY_DETECT_MODE_1:
+	case WM8915_ACCESSORY_DETECT_MODE_2:
+	case WM8915_HEADPHONE_DETECT_1:
+	case WM8915_HEADPHONE_DETECT_2:
+	case WM8915_MIC_DETECT_1:
+	case WM8915_MIC_DETECT_2:
+	case WM8915_MIC_DETECT_3:
+	case WM8915_CHARGE_PUMP_1:
+	case WM8915_CHARGE_PUMP_2:
+	case WM8915_DC_SERVO_1:
+	case WM8915_DC_SERVO_2:
+	case WM8915_DC_SERVO_3:
+	case WM8915_DC_SERVO_5:
+	case WM8915_DC_SERVO_6:
+	case WM8915_DC_SERVO_7:
+	case WM8915_DC_SERVO_READBACK_0:
+	case WM8915_ANALOGUE_HP_1:
+	case WM8915_ANALOGUE_HP_2:
+	case WM8915_CHIP_REVISION:
+	case WM8915_CONTROL_INTERFACE_1:
+	case WM8915_WRITE_SEQUENCER_CTRL_1:
+	case WM8915_WRITE_SEQUENCER_CTRL_2:
+	case WM8915_AIF_CLOCKING_1:
+	case WM8915_AIF_CLOCKING_2:
+	case WM8915_CLOCKING_1:
+	case WM8915_CLOCKING_2:
+	case WM8915_AIF_RATE:
+	case WM8915_FLL_CONTROL_1:
+	case WM8915_FLL_CONTROL_2:
+	case WM8915_FLL_CONTROL_3:
+	case WM8915_FLL_CONTROL_4:
+	case WM8915_FLL_CONTROL_5:
+	case WM8915_FLL_CONTROL_6:
+	case WM8915_FLL_EFS_1:
+	case WM8915_FLL_EFS_2:
+	case WM8915_AIF1_CONTROL:
+	case WM8915_AIF1_BCLK:
+	case WM8915_AIF1_TX_LRCLK_1:
+	case WM8915_AIF1_TX_LRCLK_2:
+	case WM8915_AIF1_RX_LRCLK_1:
+	case WM8915_AIF1_RX_LRCLK_2:
+	case WM8915_AIF1TX_DATA_CONFIGURATION_1:
+	case WM8915_AIF1TX_DATA_CONFIGURATION_2:
+	case WM8915_AIF1RX_DATA_CONFIGURATION:
+	case WM8915_AIF1TX_CHANNEL_0_CONFIGURATION:
+	case WM8915_AIF1TX_CHANNEL_1_CONFIGURATION:
+	case WM8915_AIF1TX_CHANNEL_2_CONFIGURATION:
+	case WM8915_AIF1TX_CHANNEL_3_CONFIGURATION:
+	case WM8915_AIF1TX_CHANNEL_4_CONFIGURATION:
+	case WM8915_AIF1TX_CHANNEL_5_CONFIGURATION:
+	case WM8915_AIF1RX_CHANNEL_0_CONFIGURATION:
+	case WM8915_AIF1RX_CHANNEL_1_CONFIGURATION:
+	case WM8915_AIF1RX_CHANNEL_2_CONFIGURATION:
+	case WM8915_AIF1RX_CHANNEL_3_CONFIGURATION:
+	case WM8915_AIF1RX_CHANNEL_4_CONFIGURATION:
+	case WM8915_AIF1RX_CHANNEL_5_CONFIGURATION:
+	case WM8915_AIF1RX_MONO_CONFIGURATION:
+	case WM8915_AIF1TX_TEST:
+	case WM8915_AIF2_CONTROL:
+	case WM8915_AIF2_BCLK:
+	case WM8915_AIF2_TX_LRCLK_1:
+	case WM8915_AIF2_TX_LRCLK_2:
+	case WM8915_AIF2_RX_LRCLK_1:
+	case WM8915_AIF2_RX_LRCLK_2:
+	case WM8915_AIF2TX_DATA_CONFIGURATION_1:
+	case WM8915_AIF2TX_DATA_CONFIGURATION_2:
+	case WM8915_AIF2RX_DATA_CONFIGURATION:
+	case WM8915_AIF2TX_CHANNEL_0_CONFIGURATION:
+	case WM8915_AIF2TX_CHANNEL_1_CONFIGURATION:
+	case WM8915_AIF2RX_CHANNEL_0_CONFIGURATION:
+	case WM8915_AIF2RX_CHANNEL_1_CONFIGURATION:
+	case WM8915_AIF2RX_MONO_CONFIGURATION:
+	case WM8915_AIF2TX_TEST:
+	case WM8915_DSP1_TX_LEFT_VOLUME:
+	case WM8915_DSP1_TX_RIGHT_VOLUME:
+	case WM8915_DSP1_RX_LEFT_VOLUME:
+	case WM8915_DSP1_RX_RIGHT_VOLUME:
+	case WM8915_DSP1_TX_FILTERS:
+	case WM8915_DSP1_RX_FILTERS_1:
+	case WM8915_DSP1_RX_FILTERS_2:
+	case WM8915_DSP1_DRC_1:
+	case WM8915_DSP1_DRC_2:
+	case WM8915_DSP1_DRC_3:
+	case WM8915_DSP1_DRC_4:
+	case WM8915_DSP1_DRC_5:
+	case WM8915_DSP1_RX_EQ_GAINS_1:
+	case WM8915_DSP1_RX_EQ_GAINS_2:
+	case WM8915_DSP1_RX_EQ_BAND_1_A:
+	case WM8915_DSP1_RX_EQ_BAND_1_B:
+	case WM8915_DSP1_RX_EQ_BAND_1_PG:
+	case WM8915_DSP1_RX_EQ_BAND_2_A:
+	case WM8915_DSP1_RX_EQ_BAND_2_B:
+	case WM8915_DSP1_RX_EQ_BAND_2_C:
+	case WM8915_DSP1_RX_EQ_BAND_2_PG:
+	case WM8915_DSP1_RX_EQ_BAND_3_A:
+	case WM8915_DSP1_RX_EQ_BAND_3_B:
+	case WM8915_DSP1_RX_EQ_BAND_3_C:
+	case WM8915_DSP1_RX_EQ_BAND_3_PG:
+	case WM8915_DSP1_RX_EQ_BAND_4_A:
+	case WM8915_DSP1_RX_EQ_BAND_4_B:
+	case WM8915_DSP1_RX_EQ_BAND_4_C:
+	case WM8915_DSP1_RX_EQ_BAND_4_PG:
+	case WM8915_DSP1_RX_EQ_BAND_5_A:
+	case WM8915_DSP1_RX_EQ_BAND_5_B:
+	case WM8915_DSP1_RX_EQ_BAND_5_PG:
+	case WM8915_DSP2_TX_LEFT_VOLUME:
+	case WM8915_DSP2_TX_RIGHT_VOLUME:
+	case WM8915_DSP2_RX_LEFT_VOLUME:
+	case WM8915_DSP2_RX_RIGHT_VOLUME:
+	case WM8915_DSP2_TX_FILTERS:
+	case WM8915_DSP2_RX_FILTERS_1:
+	case WM8915_DSP2_RX_FILTERS_2:
+	case WM8915_DSP2_DRC_1:
+	case WM8915_DSP2_DRC_2:
+	case WM8915_DSP2_DRC_3:
+	case WM8915_DSP2_DRC_4:
+	case WM8915_DSP2_DRC_5:
+	case WM8915_DSP2_RX_EQ_GAINS_1:
+	case WM8915_DSP2_RX_EQ_GAINS_2:
+	case WM8915_DSP2_RX_EQ_BAND_1_A:
+	case WM8915_DSP2_RX_EQ_BAND_1_B:
+	case WM8915_DSP2_RX_EQ_BAND_1_PG:
+	case WM8915_DSP2_RX_EQ_BAND_2_A:
+	case WM8915_DSP2_RX_EQ_BAND_2_B:
+	case WM8915_DSP2_RX_EQ_BAND_2_C:
+	case WM8915_DSP2_RX_EQ_BAND_2_PG:
+	case WM8915_DSP2_RX_EQ_BAND_3_A:
+	case WM8915_DSP2_RX_EQ_BAND_3_B:
+	case WM8915_DSP2_RX_EQ_BAND_3_C:
+	case WM8915_DSP2_RX_EQ_BAND_3_PG:
+	case WM8915_DSP2_RX_EQ_BAND_4_A:
+	case WM8915_DSP2_RX_EQ_BAND_4_B:
+	case WM8915_DSP2_RX_EQ_BAND_4_C:
+	case WM8915_DSP2_RX_EQ_BAND_4_PG:
+	case WM8915_DSP2_RX_EQ_BAND_5_A:
+	case WM8915_DSP2_RX_EQ_BAND_5_B:
+	case WM8915_DSP2_RX_EQ_BAND_5_PG:
+	case WM8915_DAC1_MIXER_VOLUMES:
+	case WM8915_DAC1_LEFT_MIXER_ROUTING:
+	case WM8915_DAC1_RIGHT_MIXER_ROUTING:
+	case WM8915_DAC2_MIXER_VOLUMES:
+	case WM8915_DAC2_LEFT_MIXER_ROUTING:
+	case WM8915_DAC2_RIGHT_MIXER_ROUTING:
+	case WM8915_DSP1_TX_LEFT_MIXER_ROUTING:
+	case WM8915_DSP1_TX_RIGHT_MIXER_ROUTING:
+	case WM8915_DSP2_TX_LEFT_MIXER_ROUTING:
+	case WM8915_DSP2_TX_RIGHT_MIXER_ROUTING:
+	case WM8915_DSP_TX_MIXER_SELECT:
+	case WM8915_DAC_SOFTMUTE:
+	case WM8915_OVERSAMPLING:
+	case WM8915_SIDETONE:
+	case WM8915_GPIO_1:
+	case WM8915_GPIO_2:
+	case WM8915_GPIO_3:
+	case WM8915_GPIO_4:
+	case WM8915_GPIO_5:
+	case WM8915_PULL_CONTROL_1:
+	case WM8915_PULL_CONTROL_2:
+	case WM8915_INTERRUPT_STATUS_1:
+	case WM8915_INTERRUPT_STATUS_2:
+	case WM8915_INTERRUPT_RAW_STATUS_2:
+	case WM8915_INTERRUPT_STATUS_1_MASK:
+	case WM8915_INTERRUPT_STATUS_2_MASK:
+	case WM8915_INTERRUPT_CONTROL:
+	case WM8915_LEFT_PDM_SPEAKER:
+	case WM8915_RIGHT_PDM_SPEAKER:
+	case WM8915_PDM_SPEAKER_MUTE_SEQUENCE:
+	case WM8915_PDM_SPEAKER_VOLUME:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static int wm8915_volatile_register(struct snd_soc_codec *codec,
+				    unsigned int reg)
+{
+	switch (reg) {
+	case WM8915_SOFTWARE_RESET:
+	case WM8915_CHIP_REVISION:
+	case WM8915_LDO_1:
+	case WM8915_LDO_2:
+	case WM8915_INTERRUPT_STATUS_1:
+	case WM8915_INTERRUPT_STATUS_2:
+	case WM8915_INTERRUPT_RAW_STATUS_2:
+	case WM8915_DC_SERVO_READBACK_0:
+	case WM8915_DC_SERVO_2:
+	case WM8915_DC_SERVO_6:
+	case WM8915_DC_SERVO_7:
+	case WM8915_FLL_CONTROL_6:
+	case WM8915_MIC_DETECT_3:
+	case WM8915_HEADPHONE_DETECT_1:
+	case WM8915_HEADPHONE_DETECT_2:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static int wm8915_reset(struct snd_soc_codec *codec)
+{
+	return snd_soc_write(codec, WM8915_SOFTWARE_RESET, 0x8915);
+}
+
+static int wm8915_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
+			snd_soc_update_bits(codec, WM8915_POWER_MANAGEMENT_1,
+					    WM8915_BG_ENA, WM8915_BG_ENA);
+			msleep(2);
+		}
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			ret = regulator_bulk_enable(ARRAY_SIZE(wm8915->supplies),
+						    wm8915->supplies);
+			if (ret != 0) {
+				dev_err(codec->dev,
+					"Failed to enable supplies: %d\n",
+					ret);
+				return ret;
+			}
+
+			if (wm8915->pdata.ldo_ena >= 0) {
+				gpio_set_value_cansleep(wm8915->pdata.ldo_ena,
+							1);
+				msleep(5);
+			}
+
+			codec->cache_only = false;
+			snd_soc_cache_sync(codec);
+		}
+
+		snd_soc_update_bits(codec, WM8915_POWER_MANAGEMENT_1,
+				    WM8915_BG_ENA, 0);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		codec->cache_only = true;
+		if (wm8915->pdata.ldo_ena >= 0)
+			gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 0);
+		regulator_bulk_disable(ARRAY_SIZE(wm8915->supplies),
+				       wm8915->supplies);
+		break;
+	}
+
+	codec->dapm.bias_level = level;
+
+	return 0;
+}
+
+static int wm8915_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	int aifctrl = 0;
+	int bclk = 0;
+	int lrclk_tx = 0;
+	int lrclk_rx = 0;
+	int aifctrl_reg, bclk_reg, lrclk_tx_reg, lrclk_rx_reg;
+
+	switch (dai->id) {
+	case 0:
+		aifctrl_reg = WM8915_AIF1_CONTROL;
+		bclk_reg = WM8915_AIF1_BCLK;
+		lrclk_tx_reg = WM8915_AIF1_TX_LRCLK_2;
+		lrclk_rx_reg = WM8915_AIF1_RX_LRCLK_2;
+		break;
+	case 1:
+		aifctrl_reg = WM8915_AIF2_CONTROL;
+		bclk_reg = WM8915_AIF2_BCLK;
+		lrclk_tx_reg = WM8915_AIF2_TX_LRCLK_2;
+		lrclk_rx_reg = WM8915_AIF2_RX_LRCLK_2;
+		break;
+	default:
+		BUG();
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		bclk |= WM8915_AIF1_BCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		lrclk_tx |= WM8915_AIF1TX_LRCLK_INV;
+		lrclk_rx |= WM8915_AIF1RX_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		bclk |= WM8915_AIF1_BCLK_INV;
+		lrclk_tx |= WM8915_AIF1TX_LRCLK_INV;
+		lrclk_rx |= WM8915_AIF1RX_LRCLK_INV;
+		break;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		lrclk_tx |= WM8915_AIF1TX_LRCLK_MSTR;
+		lrclk_rx |= WM8915_AIF1RX_LRCLK_MSTR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		bclk |= WM8915_AIF1_BCLK_MSTR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		bclk |= WM8915_AIF1_BCLK_MSTR;
+		lrclk_tx |= WM8915_AIF1TX_LRCLK_MSTR;
+		lrclk_rx |= WM8915_AIF1RX_LRCLK_MSTR;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		aifctrl |= 1;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		aifctrl |= 2;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aifctrl |= 3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, aifctrl_reg, WM8915_AIF1_FMT_MASK, aifctrl);
+	snd_soc_update_bits(codec, bclk_reg,
+			    WM8915_AIF1_BCLK_INV | WM8915_AIF1_BCLK_MSTR,
+			    bclk);
+	snd_soc_update_bits(codec, lrclk_tx_reg,
+			    WM8915_AIF1TX_LRCLK_INV |
+			    WM8915_AIF1TX_LRCLK_MSTR,
+			    lrclk_tx);
+	snd_soc_update_bits(codec, lrclk_rx_reg,
+			    WM8915_AIF1RX_LRCLK_INV |
+			    WM8915_AIF1RX_LRCLK_MSTR,
+			    lrclk_rx);
+
+	return 0;
+}
+
+static const int bclk_divs[] = {
+	1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96
+};
+
+static const int dsp_divs[] = {
+	48000, 32000, 16000, 8000
+};
+
+static int wm8915_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	int bits, i, bclk_rate, best, cur_val;
+	int aifdata = 0;
+	int bclk = 0;
+	int lrclk = 0;
+	int dsp = 0;
+	int aifdata_reg, bclk_reg, lrclk_reg, dsp_shift;
+
+	if (!wm8915->sysclk) {
+		dev_err(codec->dev, "SYSCLK not configured\n");
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case 0:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+		    (snd_soc_read(codec, WM8915_GPIO_1)) & WM8915_GP1_FN_MASK) {
+			aifdata_reg = WM8915_AIF1RX_DATA_CONFIGURATION;
+			lrclk_reg = WM8915_AIF1_RX_LRCLK_1;
+		} else {
+			aifdata_reg = WM8915_AIF1TX_DATA_CONFIGURATION_1;
+			lrclk_reg = WM8915_AIF1_TX_LRCLK_1;
+		}
+		bclk_reg = WM8915_AIF1_BCLK;
+		dsp_shift = 0;
+		break;
+	case 1:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+		    (snd_soc_read(codec, WM8915_GPIO_2)) & WM8915_GP2_FN_MASK) {
+			aifdata_reg = WM8915_AIF2RX_DATA_CONFIGURATION;
+			lrclk_reg = WM8915_AIF2_RX_LRCLK_1;
+		} else {
+			aifdata_reg = WM8915_AIF2TX_DATA_CONFIGURATION_1;
+			lrclk_reg = WM8915_AIF2_TX_LRCLK_1;
+		}
+		bclk_reg = WM8915_AIF2_BCLK;
+		dsp_shift = WM8915_DSP2_DIV_SHIFT;
+		break;
+	default:
+		BUG();
+		return -EINVAL;
+	}
+
+	bclk_rate = snd_soc_params_to_bclk(params);
+	if (bclk_rate < 0) {
+		dev_err(codec->dev, "Unsupported BCLK rate: %d\n", bclk_rate);
+		return bclk_rate;
+	}
+
+	/* Needs looking at for TDM */
+	bits = snd_pcm_format_width(params_format(params));
+	if (bits < 0)
+		return bits;
+	aifdata |= (bits << WM8915_AIF1TX_WL_SHIFT) | bits;
+
+	for (i = 0; i < ARRAY_SIZE(dsp_divs); i++) {
+		if (dsp_divs[i] == params_rate(params))
+			break;
+	}
+	if (i == ARRAY_SIZE(dsp_divs)) {
+		dev_err(codec->dev, "Unsupported sample rate %dHz\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+	dsp |= i << dsp_shift;
+
+	/* Pick a divisor for BCLK as close as we can get to ideal */
+	best = 0;
+	for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+		cur_val = (wm8915->sysclk / bclk_divs[i]) - bclk_rate;
+		if (cur_val < 0) /* BCLK table is sorted */
+			break;
+		best = i;
+	}
+	bclk_rate = wm8915->sysclk / bclk_divs[best];
+	dev_dbg(dai->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n",
+		bclk_divs[best], bclk_rate);
+	bclk |= best;
+
+	lrclk = bclk_rate / params_rate(params);
+	dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n",
+		lrclk, bclk_rate / lrclk);
+
+	snd_soc_update_bits(codec, aifdata_reg,
+			    WM8915_AIF1TX_WL_MASK |
+			    WM8915_AIF1TX_SLOT_LEN_MASK,
+			    aifdata);
+	snd_soc_update_bits(codec, bclk_reg, WM8915_AIF1_BCLK_DIV_MASK, bclk);
+	snd_soc_update_bits(codec, lrclk_reg, WM8915_AIF1RX_RATE_MASK,
+			    lrclk);
+	snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_2,
+			    WM8915_DSP1_DIV_SHIFT << dsp_shift, dsp);
+
+	wm8915->rx_rate[dai->id] = params_rate(params);
+
+	return 0;
+}
+
+static int wm8915_set_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	int lfclk = 0;
+	int ratediv = 0;
+	int src;
+	int old;
+
+	/* Disable SYSCLK while we reconfigure */
+	old = snd_soc_read(codec, WM8915_AIF_CLOCKING_1);
+	snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
+			    WM8915_SYSCLK_ENA, 0);
+
+	switch (clk_id) {
+	case WM8915_SYSCLK_MCLK1:
+		wm8915->sysclk = freq;
+		src = 0;
+		break;
+	case WM8915_SYSCLK_MCLK2:
+		wm8915->sysclk = freq;
+		src = 1;
+		break;
+	case WM8915_SYSCLK_FLL:
+		wm8915->sysclk = freq;
+		src = 2;
+		break;
+	default:
+		dev_err(codec->dev, "Unsupported clock source %d\n", clk_id);
+		return -EINVAL;
+	}
+
+	switch (wm8915->sysclk) {
+	case 6144000:
+		snd_soc_update_bits(codec, WM8915_AIF_RATE,
+				    WM8915_SYSCLK_RATE, 0);
+		break;
+	case 24576000:
+		ratediv = WM8915_SYSCLK_DIV;
+	case 12288000:
+		snd_soc_update_bits(codec, WM8915_AIF_RATE,
+				    WM8915_SYSCLK_RATE, WM8915_SYSCLK_RATE);
+		break;
+	case 32000:
+	case 32768:
+		lfclk = WM8915_LFCLK_ENA;
+		break;
+	default:
+		dev_warn(codec->dev, "Unsupported clock rate %dHz\n",
+			 wm8915->sysclk);
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
+			    WM8915_SYSCLK_SRC_MASK | WM8915_SYSCLK_DIV_MASK,
+			    src << WM8915_SYSCLK_SRC_SHIFT | ratediv);
+	snd_soc_update_bits(codec, WM8915_CLOCKING_1, WM8915_LFCLK_ENA, lfclk);
+	snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
+			    WM8915_SYSCLK_ENA, old);
+
+	return 0;
+}
+
+struct _fll_div {
+	u16 fll_fratio;
+	u16 fll_outdiv;
+	u16 fll_refclk_div;
+	u16 fll_loop_gain;
+	u16 fll_ref_freq;
+	u16 n;
+	u16 theta;
+	u16 lambda;
+};
+
+static struct {
+	unsigned int min;
+	unsigned int max;
+	u16 fll_fratio;
+	int ratio;
+} fll_fratios[] = {
+	{       0,    64000, 4, 16 },
+	{   64000,   128000, 3,  8 },
+	{  128000,   256000, 2,  4 },
+	{  256000,  1000000, 1,  2 },
+	{ 1000000, 13500000, 0,  1 },
+};
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+		       unsigned int Fout)
+{
+	unsigned int target;
+	unsigned int div;
+	unsigned int fratio, gcd_fll;
+	int i;
+
+	/* Fref must be <=13.5MHz */
+	div = 1;
+	fll_div->fll_refclk_div = 0;
+	while ((Fref / div) > 13500000) {
+		div *= 2;
+		fll_div->fll_refclk_div++;
+
+		if (div > 8) {
+			pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+			       Fref);
+			return -EINVAL;
+		}
+	}
+
+	pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
+
+	/* Apply the division for our remaining calculations */
+	Fref /= div;
+
+	if (Fref >= 3000000)
+		fll_div->fll_loop_gain = 5;
+	else
+		fll_div->fll_loop_gain = 0;
+
+	if (Fref >= 48000)
+		fll_div->fll_ref_freq = 0;
+	else
+		fll_div->fll_ref_freq = 1;
+
+	/* Fvco should be 90-100MHz; don't check the upper bound */
+	div = 2;
+	while (Fout * div < 90000000) {
+		div++;
+		if (div > 64) {
+			pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+			       Fout);
+			return -EINVAL;
+		}
+	}
+	target = Fout * div;
+	fll_div->fll_outdiv = div - 1;
+
+	pr_debug("FLL Fvco=%dHz\n", target);
+
+	/* Find an appropraite FLL_FRATIO and factor it out of the target */
+	for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+		if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+			fll_div->fll_fratio = fll_fratios[i].fll_fratio;
+			fratio = fll_fratios[i].ratio;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(fll_fratios)) {
+		pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
+		return -EINVAL;
+	}
+
+	fll_div->n = target / (fratio * Fref);
+
+	if (target % Fref == 0) {
+		fll_div->theta = 0;
+		fll_div->lambda = 0;
+	} else {
+		gcd_fll = gcd(target, fratio * Fref);
+
+		fll_div->theta = (target - (fll_div->n * fratio * Fref))
+			/ gcd_fll;
+		fll_div->lambda = (fratio * Fref) / gcd_fll;
+	}
+
+	pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
+		 fll_div->n, fll_div->theta, fll_div->lambda);
+	pr_debug("FLL_FRATIO=%x FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
+		 fll_div->fll_fratio, fll_div->fll_outdiv,
+		 fll_div->fll_refclk_div);
+
+	return 0;
+}
+
+static int wm8915_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+			  unsigned int Fref, unsigned int Fout)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	struct _fll_div fll_div;
+	unsigned long timeout;
+	int ret, reg;
+
+	/* Any change? */
+	if (source == wm8915->fll_src && Fref == wm8915->fll_fref &&
+	    Fout == wm8915->fll_fout)
+		return 0;
+
+	if (Fout == 0) {
+		dev_dbg(codec->dev, "FLL disabled\n");
+
+		wm8915->fll_fref = 0;
+		wm8915->fll_fout = 0;
+
+		snd_soc_update_bits(codec, WM8915_FLL_CONTROL_1,
+				    WM8915_FLL_ENA, 0);
+
+		return 0;
+	}
+
+	ret = fll_factors(&fll_div, Fref, Fout);
+	if (ret != 0)
+		return ret;
+
+	switch (source) {
+	case WM8915_FLL_MCLK1:
+		reg = 0;
+		break;
+	case WM8915_FLL_MCLK2:
+		reg = 1;
+	case WM8915_FLL_DACLRCLK1:
+		reg = 2;
+		break;
+	case WM8915_FLL_BCLK1:
+		reg = 3;
+		break;
+	default:
+		dev_err(codec->dev, "Unknown FLL source %d\n", ret);
+		return -EINVAL;
+	}
+
+	reg |= fll_div.fll_refclk_div << WM8915_FLL_REFCLK_DIV_SHIFT;
+	reg |= fll_div.fll_ref_freq << WM8915_FLL_REF_FREQ_SHIFT;
+
+	snd_soc_update_bits(codec, WM8915_FLL_CONTROL_5,
+			    WM8915_FLL_REFCLK_DIV_MASK | WM8915_FLL_REF_FREQ |
+			    WM8915_FLL_REFCLK_SRC_MASK, reg);
+
+	reg = 0;
+	if (fll_div.theta || fll_div.lambda)
+		reg |= WM8915_FLL_EFS_ENA | (3 << WM8915_FLL_LFSR_SEL_SHIFT);
+	else
+		reg |= 1 << WM8915_FLL_LFSR_SEL_SHIFT;
+	snd_soc_write(codec, WM8915_FLL_EFS_2, reg);
+
+	snd_soc_update_bits(codec, WM8915_FLL_CONTROL_2,
+			    WM8915_FLL_OUTDIV_MASK |
+			    WM8915_FLL_FRATIO_MASK,
+			    (fll_div.fll_outdiv << WM8915_FLL_OUTDIV_SHIFT) |
+			    (fll_div.fll_fratio));
+
+	snd_soc_write(codec, WM8915_FLL_CONTROL_3, fll_div.theta);
+
+	snd_soc_update_bits(codec, WM8915_FLL_CONTROL_4,
+			    WM8915_FLL_N_MASK | WM8915_FLL_LOOP_GAIN_MASK,
+			    (fll_div.n << WM8915_FLL_N_SHIFT) |
+			    fll_div.fll_loop_gain);
+
+	snd_soc_write(codec, WM8915_FLL_EFS_1, fll_div.lambda);
+
+	snd_soc_update_bits(codec, WM8915_FLL_CONTROL_1,
+			    WM8915_FLL_ENA, WM8915_FLL_ENA);
+
+	/* The FLL supports live reconfiguration - kick that in case we were
+	 * already enabled.
+	 */
+	snd_soc_write(codec, WM8915_FLL_CONTROL_6, WM8915_FLL_SWITCH_CLK);
+
+	/* Wait for the FLL to lock, using the interrupt if possible */
+	if (Fref > 1000000)
+		timeout = usecs_to_jiffies(300);
+	else
+		timeout = msecs_to_jiffies(2);
+
+	wait_for_completion_timeout(&wm8915->fll_lock, timeout);
+
+	dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
+
+	wm8915->fll_fref = Fref;
+	wm8915->fll_fout = Fout;
+	wm8915->fll_src = source;
+
+	return 0;
+}
+
+#ifdef CONFIG_GPIOLIB
+static inline struct wm8915_priv *gpio_to_wm8915(struct gpio_chip *chip)
+{
+	return container_of(chip, struct wm8915_priv, gpio_chip);
+}
+
+static void wm8915_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct wm8915_priv *wm8915 = gpio_to_wm8915(chip);
+	struct snd_soc_codec *codec = wm8915->codec;
+
+	snd_soc_update_bits(codec, WM8915_GPIO_1 + offset,
+			    WM8915_GP1_LVL, !!value << WM8915_GP1_LVL_SHIFT);
+}
+
+static int wm8915_gpio_direction_out(struct gpio_chip *chip,
+				     unsigned offset, int value)
+{
+	struct wm8915_priv *wm8915 = gpio_to_wm8915(chip);
+	struct snd_soc_codec *codec = wm8915->codec;
+	int val;
+
+	val = (1 << WM8915_GP1_FN_SHIFT) | (!!value << WM8915_GP1_LVL_SHIFT);
+
+	return snd_soc_update_bits(codec, WM8915_GPIO_1 + offset,
+				   WM8915_GP1_FN_MASK | WM8915_GP1_DIR |
+				   WM8915_GP1_LVL, val);
+}
+
+static int wm8915_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct wm8915_priv *wm8915 = gpio_to_wm8915(chip);
+	struct snd_soc_codec *codec = wm8915->codec;
+	int ret;
+
+	ret = snd_soc_read(codec, WM8915_GPIO_1 + offset);
+	if (ret < 0)
+		return ret;
+
+	return (ret & WM8915_GP1_LVL) != 0;
+}
+
+static int wm8915_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+	struct wm8915_priv *wm8915 = gpio_to_wm8915(chip);
+	struct snd_soc_codec *codec = wm8915->codec;
+
+	return snd_soc_update_bits(codec, WM8915_GPIO_1 + offset,
+				   WM8915_GP1_FN_MASK | WM8915_GP1_DIR,
+				   (1 << WM8915_GP1_FN_SHIFT) |
+				   (1 << WM8915_GP1_DIR_SHIFT));
+}
+
+static struct gpio_chip wm8915_template_chip = {
+	.label			= "wm8915",
+	.owner			= THIS_MODULE,
+	.direction_output	= wm8915_gpio_direction_out,
+	.set			= wm8915_gpio_set,
+	.direction_input	= wm8915_gpio_direction_in,
+	.get			= wm8915_gpio_get,
+	.can_sleep		= 1,
+};
+
+static void wm8915_init_gpio(struct snd_soc_codec *codec)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	wm8915->gpio_chip = wm8915_template_chip;
+	wm8915->gpio_chip.ngpio = 5;
+	wm8915->gpio_chip.dev = codec->dev;
+
+	if (wm8915->pdata.gpio_base)
+		wm8915->gpio_chip.base = wm8915->pdata.gpio_base;
+	else
+		wm8915->gpio_chip.base = -1;
+
+	ret = gpiochip_add(&wm8915->gpio_chip);
+	if (ret != 0)
+		dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+}
+
+static void wm8915_free_gpio(struct snd_soc_codec *codec)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	ret = gpiochip_remove(&wm8915->gpio_chip);
+	if (ret != 0)
+		dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
+}
+#else
+static void wm8915_init_gpio(struct snd_soc_codec *codec)
+{
+}
+
+static void wm8915_free_gpio(struct snd_soc_codec *codec)
+{
+}
+#endif
+
+/**
+ * wm8915_detect - Enable default WM8915 jack detection
+ *
+ * The WM8915 has advanced accessory detection support for headsets.
+ * This function provides a default implementation which integrates
+ * the majority of this functionality with minimal user configuration.
+ *
+ * This will detect headset, headphone and short circuit button and
+ * will also detect inverted microphone ground connections and update
+ * the polarity of the connections.
+ */
+int wm8915_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
+		  wm8915_polarity_fn polarity_cb)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+
+	wm8915->jack = jack;
+	wm8915->detecting = true;
+	wm8915->polarity_cb = polarity_cb;
+
+	if (wm8915->polarity_cb)
+		wm8915->polarity_cb(codec, 0);
+
+	/* Clear discarge to avoid noise during detection */
+	snd_soc_update_bits(codec, WM8915_MICBIAS_1,
+			    WM8915_MICB1_DISCH, 0);
+	snd_soc_update_bits(codec, WM8915_MICBIAS_2,
+			    WM8915_MICB2_DISCH, 0);
+
+	/* LDO2 powers the microphones, SYSCLK clocks detection */
+	snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
+	snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK");
+
+	/* We start off just enabling microphone detection - even a
+	 * plain headphone will trigger detection.
+	 */
+	snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
+			    WM8915_MICD_ENA, WM8915_MICD_ENA);
+
+	/* Slowest detection rate, gives debounce for initial detection */
+	snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
+			    WM8915_MICD_RATE_MASK,
+			    WM8915_MICD_RATE_MASK);
+
+	/* Enable interrupts and we're off */
+	snd_soc_update_bits(codec, WM8915_INTERRUPT_STATUS_2_MASK,
+			    WM8915_IM_MICD_EINT, 0);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8915_detect);
+
+static void wm8915_micd(struct snd_soc_codec *codec)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	int val, reg;
+
+	val = snd_soc_read(codec, WM8915_MIC_DETECT_3);
+
+	dev_dbg(codec->dev, "Microphone event: %x\n", val);
+
+	if (!(val & WM8915_MICD_VALID)) {
+		dev_warn(codec->dev, "Microphone detection state invalid\n");
+		return;
+	}
+
+	/* No accessory, reset everything and report removal */
+	if (!(val & WM8915_MICD_STS)) {
+		dev_dbg(codec->dev, "Jack removal detected\n");
+		wm8915->jack_mic = false;
+		wm8915->detecting = true;
+		snd_soc_jack_report(wm8915->jack, 0,
+				    SND_JACK_HEADSET | SND_JACK_BTN_0);
+		snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
+				    WM8915_MICD_RATE_MASK,
+				    WM8915_MICD_RATE_MASK);
+		return;
+	}
+
+	/* If the measurement is very high we've got a microphone but
+	 * do a little debounce to account for mechanical issues.
+	 */
+	if (val & 0x400) {
+		dev_dbg(codec->dev, "Microphone detected\n");
+		snd_soc_jack_report(wm8915->jack, SND_JACK_HEADSET,
+				    SND_JACK_HEADSET | SND_JACK_BTN_0);
+		wm8915->jack_mic = true;
+		wm8915->detecting = false;
+	}
+
+	/* If we detected a lower impedence during initial startup
+	 * then we probably have the wrong polarity, flip it.  Don't
+	 * do this for the lowest impedences to speed up detection of
+	 * plain headphones.
+	 */
+	if (wm8915->detecting && (val & 0x3f0)) {
+		reg = snd_soc_read(codec, WM8915_ACCESSORY_DETECT_MODE_2);
+		reg ^= WM8915_HPOUT1FB_SRC | WM8915_MICD_SRC |
+			WM8915_MICD_BIAS_SRC;
+		snd_soc_update_bits(codec, WM8915_ACCESSORY_DETECT_MODE_2,
+				    WM8915_HPOUT1FB_SRC | WM8915_MICD_SRC |
+				    WM8915_MICD_BIAS_SRC, reg);
+
+		if (wm8915->polarity_cb)
+			wm8915->polarity_cb(codec,
+					    (reg & WM8915_MICD_SRC) != 0);
+
+		dev_dbg(codec->dev, "Set microphone polarity to %d\n",
+			(reg & WM8915_MICD_SRC) != 0);
+
+		return;
+	}
+
+	/* Don't distinguish between buttons, just report any low
+	 * impedence as BTN_0.
+	 */
+	if (val & 0x3fc) {
+		if (wm8915->jack_mic) {
+			dev_dbg(codec->dev, "Mic button detected\n");
+			snd_soc_jack_report(wm8915->jack,
+					    SND_JACK_HEADSET | SND_JACK_BTN_0,
+					    SND_JACK_HEADSET | SND_JACK_BTN_0);
+		} else {
+			dev_dbg(codec->dev, "Headphone detected\n");
+			snd_soc_jack_report(wm8915->jack,
+					    SND_JACK_HEADPHONE,
+					    SND_JACK_HEADSET |
+					    SND_JACK_BTN_0);
+			wm8915->detecting = false;
+		}
+	}
+
+	/* Increase poll rate to give better responsiveness for buttons */
+	if (!wm8915->detecting)
+		snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
+				    WM8915_MICD_RATE_MASK,
+				    5 << WM8915_MICD_RATE_SHIFT);
+}
+
+static irqreturn_t wm8915_irq(int irq, void *data)
+{
+	struct snd_soc_codec *codec = data;
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	int irq_val;
+
+	irq_val = snd_soc_read(codec, WM8915_INTERRUPT_STATUS_2);
+	if (irq_val < 0) {
+		dev_err(codec->dev, "Failed to read IRQ status: %d\n",
+			irq_val);
+		return IRQ_NONE;
+	}
+	irq_val &= ~snd_soc_read(codec, WM8915_INTERRUPT_STATUS_2_MASK);
+
+	if (irq_val & (WM8915_DCS_DONE_01_EINT | WM8915_DCS_DONE_23_EINT)) {
+		dev_dbg(codec->dev, "DC servo IRQ\n");
+		complete(&wm8915->dcs_done);
+	}
+
+	if (irq_val & WM8915_FIFOS_ERR_EINT)
+		dev_err(codec->dev, "Digital core FIFO error\n");
+
+	if (irq_val & WM8915_FLL_LOCK_EINT) {
+		dev_dbg(codec->dev, "FLL locked\n");
+		complete(&wm8915->fll_lock);
+	}
+
+	if (irq_val & WM8915_MICD_EINT)
+		wm8915_micd(codec);
+
+	if (irq_val) {
+		snd_soc_write(codec, WM8915_INTERRUPT_STATUS_2, irq_val);
+
+		return IRQ_HANDLED;
+	} else {
+		return IRQ_NONE;
+	}
+}
+
+static void wm8915_retune_mobile_pdata(struct snd_soc_codec *codec)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	struct wm8915_pdata *pdata = &wm8915->pdata;
+
+	struct snd_kcontrol_new controls[] = {
+		SOC_ENUM_EXT("DSP1 EQ Mode",
+			     wm8915->retune_mobile_enum,
+			     wm8915_get_retune_mobile_enum,
+			     wm8915_put_retune_mobile_enum),
+		SOC_ENUM_EXT("DSP2 EQ Mode",
+			     wm8915->retune_mobile_enum,
+			     wm8915_get_retune_mobile_enum,
+			     wm8915_put_retune_mobile_enum),
+	};
+	int ret, i, j;
+	const char **t;
+
+	/* We need an array of texts for the enum API but the number
+	 * of texts is likely to be less than the number of
+	 * configurations due to the sample rate dependency of the
+	 * configurations. */
+	wm8915->num_retune_mobile_texts = 0;
+	wm8915->retune_mobile_texts = NULL;
+	for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+		for (j = 0; j < wm8915->num_retune_mobile_texts; j++) {
+			if (strcmp(pdata->retune_mobile_cfgs[i].name,
+				   wm8915->retune_mobile_texts[j]) == 0)
+				break;
+		}
+
+		if (j != wm8915->num_retune_mobile_texts)
+			continue;
+
+		/* Expand the array... */
+		t = krealloc(wm8915->retune_mobile_texts,
+			     sizeof(char *) * 
+			     (wm8915->num_retune_mobile_texts + 1),
+			     GFP_KERNEL);
+		if (t == NULL)
+			continue;
+
+		/* ...store the new entry... */
+		t[wm8915->num_retune_mobile_texts] = 
+			pdata->retune_mobile_cfgs[i].name;
+
+		/* ...and remember the new version. */
+		wm8915->num_retune_mobile_texts++;
+		wm8915->retune_mobile_texts = t;
+	}
+
+	dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",
+		wm8915->num_retune_mobile_texts);
+
+	wm8915->retune_mobile_enum.max = wm8915->num_retune_mobile_texts;
+	wm8915->retune_mobile_enum.texts = wm8915->retune_mobile_texts;
+
+	ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls));
+	if (ret != 0)
+		dev_err(codec->dev,
+			"Failed to add ReTune Mobile controls: %d\n", ret);
+}
+
+static int wm8915_probe(struct snd_soc_codec *codec)
+{
+	int ret;
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	struct i2c_client *i2c = to_i2c_client(codec->dev);
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	int i, irq_flags;
+
+	wm8915->codec = codec;
+
+	init_completion(&wm8915->dcs_done);
+	init_completion(&wm8915->fll_lock);
+
+	dapm->idle_bias_off = true;
+	dapm->bias_level = SND_SOC_BIAS_OFF;
+
+	ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		goto err;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++)
+		wm8915->supplies[i].supply = wm8915_supply_names[i];
+
+	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8915->supplies),
+				 wm8915->supplies);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+		goto err;
+	}
+
+	wm8915->disable_nb[0].notifier_call = wm8915_regulator_event_0;
+	wm8915->disable_nb[1].notifier_call = wm8915_regulator_event_1;
+	wm8915->disable_nb[2].notifier_call = wm8915_regulator_event_2;
+	wm8915->disable_nb[3].notifier_call = wm8915_regulator_event_3;
+	wm8915->disable_nb[4].notifier_call = wm8915_regulator_event_4;
+	wm8915->disable_nb[5].notifier_call = wm8915_regulator_event_5;
+
+	/* This should really be moved into the regulator core */
+	for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++) {
+		ret = regulator_register_notifier(wm8915->supplies[i].consumer,
+						  &wm8915->disable_nb[i]);
+		if (ret != 0) {
+			dev_err(codec->dev,
+				"Failed to register regulator notifier: %d\n",
+				ret);
+		}
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8915->supplies),
+				    wm8915->supplies);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+		goto err_get;
+	}
+
+	if (wm8915->pdata.ldo_ena >= 0) {
+		gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 1);
+		msleep(5);
+	}
+
+	ret = snd_soc_read(codec, WM8915_SOFTWARE_RESET);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to read ID register: %d\n", ret);
+		goto err_enable;
+	}
+	if (ret != 0x8915) {
+		dev_err(codec->dev, "Device is not a WM8915, ID %x\n", ret);
+		ret = -EINVAL;
+		goto err_enable;
+	}
+
+	ret = snd_soc_read(codec, WM8915_CHIP_REVISION);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to read device revision: %d\n",
+			ret);
+		goto err_enable;
+	}
+	
+	dev_info(codec->dev, "revision %c\n",
+		 (ret & WM8915_CHIP_REV_MASK) + 'A');
+
+	if (wm8915->pdata.ldo_ena >= 0) {
+		gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 0);
+	} else {
+		ret = wm8915_reset(codec);
+		if (ret < 0) {
+			dev_err(codec->dev, "Failed to issue reset\n");
+			goto err_enable;
+		}
+	}
+
+	codec->cache_only = true;
+
+	/* Apply platform data settings */
+	snd_soc_update_bits(codec, WM8915_LINE_INPUT_CONTROL,
+			    WM8915_INL_MODE_MASK | WM8915_INR_MODE_MASK,
+			    wm8915->pdata.inl_mode << WM8915_INL_MODE_SHIFT |
+			    wm8915->pdata.inr_mode);
+
+	for (i = 0; i < ARRAY_SIZE(wm8915->pdata.gpio_default); i++) {
+		if (!wm8915->pdata.gpio_default[i])
+			continue;
+
+		snd_soc_write(codec, WM8915_GPIO_1 + i,
+			      wm8915->pdata.gpio_default[i] & 0xffff);
+	}
+
+	if (wm8915->pdata.spkmute_seq)
+		snd_soc_update_bits(codec, WM8915_PDM_SPEAKER_MUTE_SEQUENCE,
+				    WM8915_SPK_MUTE_ENDIAN |
+				    WM8915_SPK_MUTE_SEQ1_MASK,
+				    wm8915->pdata.spkmute_seq);
+
+	snd_soc_update_bits(codec, WM8915_ACCESSORY_DETECT_MODE_2,
+			    WM8915_MICD_BIAS_SRC | WM8915_HPOUT1FB_SRC |
+			    WM8915_MICD_SRC, wm8915->pdata.micdet_def);
+
+	/* Latch volume update bits */
+	snd_soc_update_bits(codec, WM8915_LEFT_LINE_INPUT_VOLUME,
+			    WM8915_IN1_VU, WM8915_IN1_VU);
+	snd_soc_update_bits(codec, WM8915_RIGHT_LINE_INPUT_VOLUME,
+			    WM8915_IN1_VU, WM8915_IN1_VU);
+
+	snd_soc_update_bits(codec, WM8915_DAC1_LEFT_VOLUME,
+			    WM8915_DAC1_VU, WM8915_DAC1_VU);
+	snd_soc_update_bits(codec, WM8915_DAC1_RIGHT_VOLUME,
+			    WM8915_DAC1_VU, WM8915_DAC1_VU);
+	snd_soc_update_bits(codec, WM8915_DAC2_LEFT_VOLUME,
+			    WM8915_DAC2_VU, WM8915_DAC2_VU);
+	snd_soc_update_bits(codec, WM8915_DAC2_RIGHT_VOLUME,
+			    WM8915_DAC2_VU, WM8915_DAC2_VU);
+
+	snd_soc_update_bits(codec, WM8915_OUTPUT1_LEFT_VOLUME,
+			    WM8915_DAC1_VU, WM8915_DAC1_VU);
+	snd_soc_update_bits(codec, WM8915_OUTPUT1_RIGHT_VOLUME,
+			    WM8915_DAC1_VU, WM8915_DAC1_VU);
+	snd_soc_update_bits(codec, WM8915_OUTPUT2_LEFT_VOLUME,
+			    WM8915_DAC2_VU, WM8915_DAC2_VU);
+	snd_soc_update_bits(codec, WM8915_OUTPUT2_RIGHT_VOLUME,
+			    WM8915_DAC2_VU, WM8915_DAC2_VU);
+
+	snd_soc_update_bits(codec, WM8915_DSP1_TX_LEFT_VOLUME,
+			    WM8915_DSP1TX_VU, WM8915_DSP1TX_VU);
+	snd_soc_update_bits(codec, WM8915_DSP1_TX_RIGHT_VOLUME,
+			    WM8915_DSP1TX_VU, WM8915_DSP1TX_VU);
+	snd_soc_update_bits(codec, WM8915_DSP2_TX_LEFT_VOLUME,
+			    WM8915_DSP2TX_VU, WM8915_DSP2TX_VU);
+	snd_soc_update_bits(codec, WM8915_DSP2_TX_RIGHT_VOLUME,
+			    WM8915_DSP2TX_VU, WM8915_DSP2TX_VU);
+
+	snd_soc_update_bits(codec, WM8915_DSP1_RX_LEFT_VOLUME,
+			    WM8915_DSP1RX_VU, WM8915_DSP1RX_VU);
+	snd_soc_update_bits(codec, WM8915_DSP1_RX_RIGHT_VOLUME,
+			    WM8915_DSP1RX_VU, WM8915_DSP1RX_VU);
+	snd_soc_update_bits(codec, WM8915_DSP2_RX_LEFT_VOLUME,
+			    WM8915_DSP2RX_VU, WM8915_DSP2RX_VU);
+	snd_soc_update_bits(codec, WM8915_DSP2_RX_RIGHT_VOLUME,
+			    WM8915_DSP2RX_VU, WM8915_DSP2RX_VU);
+
+	/* No support currently for the underclocked TDM modes and
+	 * pick a default TDM layout with each channel pair working with
+	 * slots 0 and 1. */
+	snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_0_CONFIGURATION,
+			    WM8915_AIF1RX_CHAN0_SLOTS_MASK |
+			    WM8915_AIF1RX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF1RX_CHAN0_SLOTS_SHIFT | 0);
+	snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_1_CONFIGURATION,
+			    WM8915_AIF1RX_CHAN1_SLOTS_MASK |
+			    WM8915_AIF1RX_CHAN1_START_SLOT_MASK,
+			    1 << WM8915_AIF1RX_CHAN1_SLOTS_SHIFT | 1);
+	snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_2_CONFIGURATION,
+			    WM8915_AIF1RX_CHAN2_SLOTS_MASK |
+			    WM8915_AIF1RX_CHAN2_START_SLOT_MASK,
+			    1 << WM8915_AIF1RX_CHAN2_SLOTS_SHIFT | 0);
+	snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_3_CONFIGURATION,
+			    WM8915_AIF1RX_CHAN3_SLOTS_MASK |
+			    WM8915_AIF1RX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF1RX_CHAN3_SLOTS_SHIFT | 1);
+	snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_4_CONFIGURATION,
+			    WM8915_AIF1RX_CHAN4_SLOTS_MASK |
+			    WM8915_AIF1RX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF1RX_CHAN4_SLOTS_SHIFT | 0);
+	snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_5_CONFIGURATION,
+			    WM8915_AIF1RX_CHAN5_SLOTS_MASK |
+			    WM8915_AIF1RX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF1RX_CHAN5_SLOTS_SHIFT | 1);
+
+	snd_soc_update_bits(codec, WM8915_AIF2RX_CHANNEL_0_CONFIGURATION,
+			    WM8915_AIF2RX_CHAN0_SLOTS_MASK |
+			    WM8915_AIF2RX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF2RX_CHAN0_SLOTS_SHIFT | 0);
+	snd_soc_update_bits(codec, WM8915_AIF2RX_CHANNEL_1_CONFIGURATION,
+			    WM8915_AIF2RX_CHAN1_SLOTS_MASK |
+			    WM8915_AIF2RX_CHAN1_START_SLOT_MASK,
+			    1 << WM8915_AIF2RX_CHAN1_SLOTS_SHIFT | 1);
+
+	snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_0_CONFIGURATION,
+			    WM8915_AIF1TX_CHAN0_SLOTS_MASK |
+			    WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF1TX_CHAN0_SLOTS_SHIFT | 0);
+	snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_1_CONFIGURATION,
+			    WM8915_AIF1TX_CHAN1_SLOTS_MASK |
+			    WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
+	snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_2_CONFIGURATION,
+			    WM8915_AIF1TX_CHAN2_SLOTS_MASK |
+			    WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF1TX_CHAN2_SLOTS_SHIFT | 0);
+	snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_3_CONFIGURATION,
+			    WM8915_AIF1TX_CHAN3_SLOTS_MASK |
+			    WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF1TX_CHAN3_SLOTS_SHIFT | 1);
+	snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_4_CONFIGURATION,
+			    WM8915_AIF1TX_CHAN4_SLOTS_MASK |
+			    WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF1TX_CHAN4_SLOTS_SHIFT | 0);
+	snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_5_CONFIGURATION,
+			    WM8915_AIF1TX_CHAN5_SLOTS_MASK |
+			    WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF1TX_CHAN5_SLOTS_SHIFT | 1);
+
+	snd_soc_update_bits(codec, WM8915_AIF2TX_CHANNEL_0_CONFIGURATION,
+			    WM8915_AIF2TX_CHAN0_SLOTS_MASK |
+			    WM8915_AIF2TX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF2TX_CHAN0_SLOTS_SHIFT | 0);
+	snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_1_CONFIGURATION,
+			    WM8915_AIF2TX_CHAN1_SLOTS_MASK |
+			    WM8915_AIF2TX_CHAN1_START_SLOT_MASK,
+			    1 << WM8915_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
+
+	if (wm8915->pdata.num_retune_mobile_cfgs)
+		wm8915_retune_mobile_pdata(codec);
+	else
+		snd_soc_add_controls(codec, wm8915_eq_controls,
+				     ARRAY_SIZE(wm8915_eq_controls));
+
+	/* If the TX LRCLK pins are not in LRCLK mode configure the
+	 * AIFs to source their clocks from the RX LRCLKs.
+	 */
+	if ((snd_soc_read(codec, WM8915_GPIO_1)))
+		snd_soc_update_bits(codec, WM8915_AIF1_TX_LRCLK_2,
+				    WM8915_AIF1TX_LRCLK_MODE,
+				    WM8915_AIF1TX_LRCLK_MODE);
+
+	if ((snd_soc_read(codec, WM8915_GPIO_2)))
+		snd_soc_update_bits(codec, WM8915_AIF2_TX_LRCLK_2,
+				    WM8915_AIF2TX_LRCLK_MODE,
+				    WM8915_AIF2TX_LRCLK_MODE);
+
+	regulator_bulk_disable(ARRAY_SIZE(wm8915->supplies), wm8915->supplies);
+
+	wm8915_init_gpio(codec);
+
+	if (i2c->irq) {
+		if (wm8915->pdata.irq_flags)
+			irq_flags = wm8915->pdata.irq_flags;
+		else
+			irq_flags = IRQF_TRIGGER_LOW;
+
+		irq_flags |= IRQF_ONESHOT;
+
+		ret = request_threaded_irq(i2c->irq, NULL, wm8915_irq,
+					   irq_flags, "wm8915", codec);
+		if (ret == 0) {
+			/* Unmask the interrupt */
+			snd_soc_update_bits(codec, WM8915_INTERRUPT_CONTROL,
+					    WM8915_IM_IRQ, 0);
+
+			/* Enable error reporting and DC servo status */
+			snd_soc_update_bits(codec,
+					    WM8915_INTERRUPT_STATUS_2_MASK,
+					    WM8915_IM_DCS_DONE_23_EINT |
+					    WM8915_IM_DCS_DONE_01_EINT |
+					    WM8915_IM_FLL_LOCK_EINT |
+					    WM8915_IM_FIFOS_ERR_EINT,
+					    0);
+		} else {
+			dev_err(codec->dev, "Failed to request IRQ: %d\n",
+				ret);
+		}
+	}
+
+	return 0;
+
+err_enable:
+	if (wm8915->pdata.ldo_ena >= 0)
+		gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 0);
+
+	regulator_bulk_disable(ARRAY_SIZE(wm8915->supplies), wm8915->supplies);
+err_get:
+	regulator_bulk_free(ARRAY_SIZE(wm8915->supplies), wm8915->supplies);
+err:
+	return ret;
+}
+
+static int wm8915_remove(struct snd_soc_codec *codec)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	struct i2c_client *i2c = to_i2c_client(codec->dev);
+	int i;
+
+	snd_soc_update_bits(codec, WM8915_INTERRUPT_CONTROL,
+			    WM8915_IM_IRQ, WM8915_IM_IRQ);
+
+	if (i2c->irq)
+		free_irq(i2c->irq, codec);
+
+	wm8915_free_gpio(codec);
+
+	for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++)
+		regulator_unregister_notifier(wm8915->supplies[i].consumer,
+					      &wm8915->disable_nb[i]);
+	regulator_bulk_free(ARRAY_SIZE(wm8915->supplies), wm8915->supplies);
+
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8915 = {
+	.probe =	wm8915_probe,
+	.remove =	wm8915_remove,
+	.set_bias_level = wm8915_set_bias_level,
+	.seq_notifier = wm8915_seq_notifier,
+	.reg_cache_size = WM8915_MAX_REGISTER + 1,
+	.reg_word_size = sizeof(u16),
+	.reg_cache_default = wm8915_reg,
+	.volatile_register = wm8915_volatile_register,
+	.readable_register = wm8915_readable_register,
+	.compress_type = SND_SOC_RBTREE_COMPRESSION,
+	.controls = wm8915_snd_controls,
+	.num_controls = ARRAY_SIZE(wm8915_snd_controls),
+	.dapm_widgets = wm8915_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8915_dapm_widgets),
+	.dapm_routes = wm8915_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(wm8915_dapm_routes),
+	.set_pll = wm8915_set_fll,
+};
+
+#define WM8915_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+		      SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+#define WM8915_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
+			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE |\
+			SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops wm8915_dai_ops = {
+	.set_fmt = wm8915_set_fmt,
+	.hw_params = wm8915_hw_params,
+	.set_sysclk = wm8915_set_sysclk,
+};
+
+static struct snd_soc_dai_driver wm8915_dai[] = {
+	{
+		.name = "wm8915-aif1",
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 6,
+			.rates = WM8915_RATES,
+			.formats = WM8915_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF1 Capture",
+			 .channels_min = 1,
+			 .channels_max = 6,
+			 .rates = WM8915_RATES,
+			 .formats = WM8915_FORMATS,
+		 },
+		.ops = &wm8915_dai_ops,
+	},
+	{
+		.name = "wm8915-aif2",
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8915_RATES,
+			.formats = WM8915_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF2 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = WM8915_RATES,
+			 .formats = WM8915_FORMATS,
+		 },
+		.ops = &wm8915_dai_ops,
+	},
+};
+
+static __devinit int wm8915_i2c_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
+{
+	struct wm8915_priv *wm8915;
+	int ret;
+
+	wm8915 = kzalloc(sizeof(struct wm8915_priv), GFP_KERNEL);
+	if (wm8915 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, wm8915);
+
+	if (dev_get_platdata(&i2c->dev))
+		memcpy(&wm8915->pdata, dev_get_platdata(&i2c->dev),
+		       sizeof(wm8915->pdata));
+
+	if (wm8915->pdata.ldo_ena > 0) {
+		ret = gpio_request_one(wm8915->pdata.ldo_ena,
+				       GPIOF_OUT_INIT_LOW, "WM8915 ENA");
+		if (ret < 0) {
+			dev_err(&i2c->dev, "Failed to request GPIO %d: %d\n",
+				wm8915->pdata.ldo_ena, ret);
+			goto err;
+		}
+	}
+
+	ret = snd_soc_register_codec(&i2c->dev,
+				     &soc_codec_dev_wm8915, wm8915_dai,
+				     ARRAY_SIZE(wm8915_dai));
+	if (ret < 0)
+		goto err_gpio;
+
+	return ret;
+
+err_gpio:
+	if (wm8915->pdata.ldo_ena > 0)
+		gpio_free(wm8915->pdata.ldo_ena);
+err:
+	kfree(wm8915);
+
+	return ret;
+}
+
+static __devexit int wm8915_i2c_remove(struct i2c_client *client)
+{
+	struct wm8915_priv *wm8915 = i2c_get_clientdata(client);
+
+	snd_soc_unregister_codec(&client->dev);
+	if (wm8915->pdata.ldo_ena > 0)
+		gpio_free(wm8915->pdata.ldo_ena);
+	kfree(i2c_get_clientdata(client));
+	return 0;
+}
+
+static const struct i2c_device_id wm8915_i2c_id[] = {
+	{ "wm8915", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8915_i2c_id);
+
+static struct i2c_driver wm8915_i2c_driver = {
+	.driver = {
+		.name = "wm8915",
+		.owner = THIS_MODULE,
+	},
+	.probe =    wm8915_i2c_probe,
+	.remove =   __devexit_p(wm8915_i2c_remove),
+	.id_table = wm8915_i2c_id,
+};
+
+static int __init wm8915_modinit(void)
+{
+	int ret;
+
+	ret = i2c_add_driver(&wm8915_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register WM8915 I2C driver: %d\n",
+		       ret);
+	}
+
+	return ret;
+}
+module_init(wm8915_modinit);
+
+static void __exit wm8915_exit(void)
+{
+	i2c_del_driver(&wm8915_i2c_driver);
+}
+module_exit(wm8915_exit);
+
+MODULE_DESCRIPTION("ASoC WM8915 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8915.h b/sound/soc/codecs/wm8915.h
new file mode 100644
index 000000000000..200ffd7bf953
--- /dev/null
+++ b/sound/soc/codecs/wm8915.h
@@ -0,0 +1,3717 @@
+/*
+ * wm8915.h - WM8915 audio codec interface
+ *
+ * Copyright 2011 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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.
+ */
+
+#ifndef _WM8915_H
+#define _WM8915_H
+
+#define WM8915_SYSCLK_MCLK1 1
+#define WM8915_SYSCLK_MCLK2 2
+#define WM8915_SYSCLK_FLL   3
+
+#define WM8915_FLL_MCLK1      1
+#define WM8915_FLL_MCLK2      2
+#define WM8915_FLL_DACLRCLK1  3
+#define WM8915_FLL_BCLK1      4
+
+typedef void (*wm8915_polarity_fn)(struct snd_soc_codec *codec, int polarity);
+
+int wm8915_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
+		  wm8915_polarity_fn polarity_cb);
+
+/*
+ * Register values.
+ */
+#define WM8915_SOFTWARE_RESET                   0x00
+#define WM8915_POWER_MANAGEMENT_1               0x01
+#define WM8915_POWER_MANAGEMENT_2               0x02
+#define WM8915_POWER_MANAGEMENT_3               0x03
+#define WM8915_POWER_MANAGEMENT_4               0x04
+#define WM8915_POWER_MANAGEMENT_5               0x05
+#define WM8915_POWER_MANAGEMENT_6               0x06
+#define WM8915_POWER_MANAGEMENT_7               0x07
+#define WM8915_POWER_MANAGEMENT_8               0x08
+#define WM8915_LEFT_LINE_INPUT_VOLUME           0x10
+#define WM8915_RIGHT_LINE_INPUT_VOLUME          0x11
+#define WM8915_LINE_INPUT_CONTROL               0x12
+#define WM8915_DAC1_HPOUT1_VOLUME               0x15
+#define WM8915_DAC2_HPOUT2_VOLUME               0x16
+#define WM8915_DAC1_LEFT_VOLUME                 0x18
+#define WM8915_DAC1_RIGHT_VOLUME                0x19
+#define WM8915_DAC2_LEFT_VOLUME                 0x1A
+#define WM8915_DAC2_RIGHT_VOLUME                0x1B
+#define WM8915_OUTPUT1_LEFT_VOLUME              0x1C
+#define WM8915_OUTPUT1_RIGHT_VOLUME             0x1D
+#define WM8915_OUTPUT2_LEFT_VOLUME              0x1E
+#define WM8915_OUTPUT2_RIGHT_VOLUME             0x1F
+#define WM8915_MICBIAS_1                        0x20
+#define WM8915_MICBIAS_2                        0x21
+#define WM8915_LDO_1                            0x28
+#define WM8915_LDO_2                            0x29
+#define WM8915_ACCESSORY_DETECT_MODE_1          0x30
+#define WM8915_ACCESSORY_DETECT_MODE_2          0x31
+#define WM8915_HEADPHONE_DETECT_1               0x34
+#define WM8915_HEADPHONE_DETECT_2               0x35
+#define WM8915_MIC_DETECT_1                     0x38
+#define WM8915_MIC_DETECT_2                     0x39
+#define WM8915_MIC_DETECT_3                     0x3A
+#define WM8915_CHARGE_PUMP_1                    0x40
+#define WM8915_CHARGE_PUMP_2                    0x41
+#define WM8915_DC_SERVO_1                       0x50
+#define WM8915_DC_SERVO_2                       0x51
+#define WM8915_DC_SERVO_3                       0x52
+#define WM8915_DC_SERVO_5                       0x54
+#define WM8915_DC_SERVO_6                       0x55
+#define WM8915_DC_SERVO_7                       0x56
+#define WM8915_DC_SERVO_READBACK_0              0x57
+#define WM8915_ANALOGUE_HP_1                    0x60
+#define WM8915_ANALOGUE_HP_2                    0x61
+#define WM8915_CHIP_REVISION                    0x100
+#define WM8915_CONTROL_INTERFACE_1              0x101
+#define WM8915_WRITE_SEQUENCER_CTRL_1           0x110
+#define WM8915_WRITE_SEQUENCER_CTRL_2           0x111
+#define WM8915_AIF_CLOCKING_1                   0x200
+#define WM8915_AIF_CLOCKING_2                   0x201
+#define WM8915_CLOCKING_1                       0x208
+#define WM8915_CLOCKING_2                       0x209
+#define WM8915_AIF_RATE                         0x210
+#define WM8915_FLL_CONTROL_1                    0x220
+#define WM8915_FLL_CONTROL_2                    0x221
+#define WM8915_FLL_CONTROL_3                    0x222
+#define WM8915_FLL_CONTROL_4                    0x223
+#define WM8915_FLL_CONTROL_5                    0x224
+#define WM8915_FLL_CONTROL_6                    0x225
+#define WM8915_FLL_EFS_1                        0x226
+#define WM8915_FLL_EFS_2                        0x227
+#define WM8915_AIF1_CONTROL                     0x300
+#define WM8915_AIF1_BCLK                        0x301
+#define WM8915_AIF1_TX_LRCLK_1                  0x302
+#define WM8915_AIF1_TX_LRCLK_2                  0x303
+#define WM8915_AIF1_RX_LRCLK_1                  0x304
+#define WM8915_AIF1_RX_LRCLK_2                  0x305
+#define WM8915_AIF1TX_DATA_CONFIGURATION_1      0x306
+#define WM8915_AIF1TX_DATA_CONFIGURATION_2      0x307
+#define WM8915_AIF1RX_DATA_CONFIGURATION        0x308
+#define WM8915_AIF1TX_CHANNEL_0_CONFIGURATION   0x309
+#define WM8915_AIF1TX_CHANNEL_1_CONFIGURATION   0x30A
+#define WM8915_AIF1TX_CHANNEL_2_CONFIGURATION   0x30B
+#define WM8915_AIF1TX_CHANNEL_3_CONFIGURATION   0x30C
+#define WM8915_AIF1TX_CHANNEL_4_CONFIGURATION   0x30D
+#define WM8915_AIF1TX_CHANNEL_5_CONFIGURATION   0x30E
+#define WM8915_AIF1RX_CHANNEL_0_CONFIGURATION   0x30F
+#define WM8915_AIF1RX_CHANNEL_1_CONFIGURATION   0x310
+#define WM8915_AIF1RX_CHANNEL_2_CONFIGURATION   0x311
+#define WM8915_AIF1RX_CHANNEL_3_CONFIGURATION   0x312
+#define WM8915_AIF1RX_CHANNEL_4_CONFIGURATION   0x313
+#define WM8915_AIF1RX_CHANNEL_5_CONFIGURATION   0x314
+#define WM8915_AIF1RX_MONO_CONFIGURATION        0x315
+#define WM8915_AIF1TX_TEST                      0x31A
+#define WM8915_AIF2_CONTROL                     0x320
+#define WM8915_AIF2_BCLK                        0x321
+#define WM8915_AIF2_TX_LRCLK_1                  0x322
+#define WM8915_AIF2_TX_LRCLK_2                  0x323
+#define WM8915_AIF2_RX_LRCLK_1                  0x324
+#define WM8915_AIF2_RX_LRCLK_2                  0x325
+#define WM8915_AIF2TX_DATA_CONFIGURATION_1      0x326
+#define WM8915_AIF2TX_DATA_CONFIGURATION_2      0x327
+#define WM8915_AIF2RX_DATA_CONFIGURATION        0x328
+#define WM8915_AIF2TX_CHANNEL_0_CONFIGURATION   0x329
+#define WM8915_AIF2TX_CHANNEL_1_CONFIGURATION   0x32A
+#define WM8915_AIF2RX_CHANNEL_0_CONFIGURATION   0x32B
+#define WM8915_AIF2RX_CHANNEL_1_CONFIGURATION   0x32C
+#define WM8915_AIF2RX_MONO_CONFIGURATION        0x32D
+#define WM8915_AIF2TX_TEST                      0x32F
+#define WM8915_DSP1_TX_LEFT_VOLUME              0x400
+#define WM8915_DSP1_TX_RIGHT_VOLUME             0x401
+#define WM8915_DSP1_RX_LEFT_VOLUME              0x402
+#define WM8915_DSP1_RX_RIGHT_VOLUME             0x403
+#define WM8915_DSP1_TX_FILTERS                  0x410
+#define WM8915_DSP1_RX_FILTERS_1                0x420
+#define WM8915_DSP1_RX_FILTERS_2                0x421
+#define WM8915_DSP1_DRC_1                       0x440
+#define WM8915_DSP1_DRC_2                       0x441
+#define WM8915_DSP1_DRC_3                       0x442
+#define WM8915_DSP1_DRC_4                       0x443
+#define WM8915_DSP1_DRC_5                       0x444
+#define WM8915_DSP1_RX_EQ_GAINS_1               0x480
+#define WM8915_DSP1_RX_EQ_GAINS_2               0x481
+#define WM8915_DSP1_RX_EQ_BAND_1_A              0x482
+#define WM8915_DSP1_RX_EQ_BAND_1_B              0x483
+#define WM8915_DSP1_RX_EQ_BAND_1_PG             0x484
+#define WM8915_DSP1_RX_EQ_BAND_2_A              0x485
+#define WM8915_DSP1_RX_EQ_BAND_2_B              0x486
+#define WM8915_DSP1_RX_EQ_BAND_2_C              0x487
+#define WM8915_DSP1_RX_EQ_BAND_2_PG             0x488
+#define WM8915_DSP1_RX_EQ_BAND_3_A              0x489
+#define WM8915_DSP1_RX_EQ_BAND_3_B              0x48A
+#define WM8915_DSP1_RX_EQ_BAND_3_C              0x48B
+#define WM8915_DSP1_RX_EQ_BAND_3_PG             0x48C
+#define WM8915_DSP1_RX_EQ_BAND_4_A              0x48D
+#define WM8915_DSP1_RX_EQ_BAND_4_B              0x48E
+#define WM8915_DSP1_RX_EQ_BAND_4_C              0x48F
+#define WM8915_DSP1_RX_EQ_BAND_4_PG             0x490
+#define WM8915_DSP1_RX_EQ_BAND_5_A              0x491
+#define WM8915_DSP1_RX_EQ_BAND_5_B              0x492
+#define WM8915_DSP1_RX_EQ_BAND_5_PG             0x493
+#define WM8915_DSP2_TX_LEFT_VOLUME              0x500
+#define WM8915_DSP2_TX_RIGHT_VOLUME             0x501
+#define WM8915_DSP2_RX_LEFT_VOLUME              0x502
+#define WM8915_DSP2_RX_RIGHT_VOLUME             0x503
+#define WM8915_DSP2_TX_FILTERS                  0x510
+#define WM8915_DSP2_RX_FILTERS_1                0x520
+#define WM8915_DSP2_RX_FILTERS_2                0x521
+#define WM8915_DSP2_DRC_1                       0x540
+#define WM8915_DSP2_DRC_2                       0x541
+#define WM8915_DSP2_DRC_3                       0x542
+#define WM8915_DSP2_DRC_4                       0x543
+#define WM8915_DSP2_DRC_5                       0x544
+#define WM8915_DSP2_RX_EQ_GAINS_1               0x580
+#define WM8915_DSP2_RX_EQ_GAINS_2               0x581
+#define WM8915_DSP2_RX_EQ_BAND_1_A              0x582
+#define WM8915_DSP2_RX_EQ_BAND_1_B              0x583
+#define WM8915_DSP2_RX_EQ_BAND_1_PG             0x584
+#define WM8915_DSP2_RX_EQ_BAND_2_A              0x585
+#define WM8915_DSP2_RX_EQ_BAND_2_B              0x586
+#define WM8915_DSP2_RX_EQ_BAND_2_C              0x587
+#define WM8915_DSP2_RX_EQ_BAND_2_PG             0x588
+#define WM8915_DSP2_RX_EQ_BAND_3_A              0x589
+#define WM8915_DSP2_RX_EQ_BAND_3_B              0x58A
+#define WM8915_DSP2_RX_EQ_BAND_3_C              0x58B
+#define WM8915_DSP2_RX_EQ_BAND_3_PG             0x58C
+#define WM8915_DSP2_RX_EQ_BAND_4_A              0x58D
+#define WM8915_DSP2_RX_EQ_BAND_4_B              0x58E
+#define WM8915_DSP2_RX_EQ_BAND_4_C              0x58F
+#define WM8915_DSP2_RX_EQ_BAND_4_PG             0x590
+#define WM8915_DSP2_RX_EQ_BAND_5_A              0x591
+#define WM8915_DSP2_RX_EQ_BAND_5_B              0x592
+#define WM8915_DSP2_RX_EQ_BAND_5_PG             0x593
+#define WM8915_DAC1_MIXER_VOLUMES               0x600
+#define WM8915_DAC1_LEFT_MIXER_ROUTING          0x601
+#define WM8915_DAC1_RIGHT_MIXER_ROUTING         0x602
+#define WM8915_DAC2_MIXER_VOLUMES               0x603
+#define WM8915_DAC2_LEFT_MIXER_ROUTING          0x604
+#define WM8915_DAC2_RIGHT_MIXER_ROUTING         0x605
+#define WM8915_DSP1_TX_LEFT_MIXER_ROUTING       0x606
+#define WM8915_DSP1_TX_RIGHT_MIXER_ROUTING      0x607
+#define WM8915_DSP2_TX_LEFT_MIXER_ROUTING       0x608
+#define WM8915_DSP2_TX_RIGHT_MIXER_ROUTING      0x609
+#define WM8915_DSP_TX_MIXER_SELECT              0x60A
+#define WM8915_DAC_SOFTMUTE                     0x610
+#define WM8915_OVERSAMPLING                     0x620
+#define WM8915_SIDETONE                         0x621
+#define WM8915_GPIO_1                           0x700
+#define WM8915_GPIO_2                           0x701
+#define WM8915_GPIO_3                           0x702
+#define WM8915_GPIO_4                           0x703
+#define WM8915_GPIO_5                           0x704
+#define WM8915_PULL_CONTROL_1                   0x720
+#define WM8915_PULL_CONTROL_2                   0x721
+#define WM8915_INTERRUPT_STATUS_1               0x730
+#define WM8915_INTERRUPT_STATUS_2               0x731
+#define WM8915_INTERRUPT_RAW_STATUS_2           0x732
+#define WM8915_INTERRUPT_STATUS_1_MASK          0x738
+#define WM8915_INTERRUPT_STATUS_2_MASK          0x739
+#define WM8915_INTERRUPT_CONTROL                0x740
+#define WM8915_LEFT_PDM_SPEAKER                 0x800
+#define WM8915_RIGHT_PDM_SPEAKER                0x801
+#define WM8915_PDM_SPEAKER_MUTE_SEQUENCE        0x802
+#define WM8915_PDM_SPEAKER_VOLUME               0x803
+#define WM8915_WRITE_SEQUENCER_0                0x3000
+#define WM8915_WRITE_SEQUENCER_1                0x3001
+#define WM8915_WRITE_SEQUENCER_2                0x3002
+#define WM8915_WRITE_SEQUENCER_3                0x3003
+#define WM8915_WRITE_SEQUENCER_4                0x3004
+#define WM8915_WRITE_SEQUENCER_5                0x3005
+#define WM8915_WRITE_SEQUENCER_6                0x3006
+#define WM8915_WRITE_SEQUENCER_7                0x3007
+#define WM8915_WRITE_SEQUENCER_8                0x3008
+#define WM8915_WRITE_SEQUENCER_9                0x3009
+#define WM8915_WRITE_SEQUENCER_10               0x300A
+#define WM8915_WRITE_SEQUENCER_11               0x300B
+#define WM8915_WRITE_SEQUENCER_12               0x300C
+#define WM8915_WRITE_SEQUENCER_13               0x300D
+#define WM8915_WRITE_SEQUENCER_14               0x300E
+#define WM8915_WRITE_SEQUENCER_15               0x300F
+#define WM8915_WRITE_SEQUENCER_16               0x3010
+#define WM8915_WRITE_SEQUENCER_17               0x3011
+#define WM8915_WRITE_SEQUENCER_18               0x3012
+#define WM8915_WRITE_SEQUENCER_19               0x3013
+#define WM8915_WRITE_SEQUENCER_20               0x3014
+#define WM8915_WRITE_SEQUENCER_21               0x3015
+#define WM8915_WRITE_SEQUENCER_22               0x3016
+#define WM8915_WRITE_SEQUENCER_23               0x3017
+#define WM8915_WRITE_SEQUENCER_24               0x3018
+#define WM8915_WRITE_SEQUENCER_25               0x3019
+#define WM8915_WRITE_SEQUENCER_26               0x301A
+#define WM8915_WRITE_SEQUENCER_27               0x301B
+#define WM8915_WRITE_SEQUENCER_28               0x301C
+#define WM8915_WRITE_SEQUENCER_29               0x301D
+#define WM8915_WRITE_SEQUENCER_30               0x301E
+#define WM8915_WRITE_SEQUENCER_31               0x301F
+#define WM8915_WRITE_SEQUENCER_32               0x3020
+#define WM8915_WRITE_SEQUENCER_33               0x3021
+#define WM8915_WRITE_SEQUENCER_34               0x3022
+#define WM8915_WRITE_SEQUENCER_35               0x3023
+#define WM8915_WRITE_SEQUENCER_36               0x3024
+#define WM8915_WRITE_SEQUENCER_37               0x3025
+#define WM8915_WRITE_SEQUENCER_38               0x3026
+#define WM8915_WRITE_SEQUENCER_39               0x3027
+#define WM8915_WRITE_SEQUENCER_40               0x3028
+#define WM8915_WRITE_SEQUENCER_41               0x3029
+#define WM8915_WRITE_SEQUENCER_42               0x302A
+#define WM8915_WRITE_SEQUENCER_43               0x302B
+#define WM8915_WRITE_SEQUENCER_44               0x302C
+#define WM8915_WRITE_SEQUENCER_45               0x302D
+#define WM8915_WRITE_SEQUENCER_46               0x302E
+#define WM8915_WRITE_SEQUENCER_47               0x302F
+#define WM8915_WRITE_SEQUENCER_48               0x3030
+#define WM8915_WRITE_SEQUENCER_49               0x3031
+#define WM8915_WRITE_SEQUENCER_50               0x3032
+#define WM8915_WRITE_SEQUENCER_51               0x3033
+#define WM8915_WRITE_SEQUENCER_52               0x3034
+#define WM8915_WRITE_SEQUENCER_53               0x3035
+#define WM8915_WRITE_SEQUENCER_54               0x3036
+#define WM8915_WRITE_SEQUENCER_55               0x3037
+#define WM8915_WRITE_SEQUENCER_56               0x3038
+#define WM8915_WRITE_SEQUENCER_57               0x3039
+#define WM8915_WRITE_SEQUENCER_58               0x303A
+#define WM8915_WRITE_SEQUENCER_59               0x303B
+#define WM8915_WRITE_SEQUENCER_60               0x303C
+#define WM8915_WRITE_SEQUENCER_61               0x303D
+#define WM8915_WRITE_SEQUENCER_62               0x303E
+#define WM8915_WRITE_SEQUENCER_63               0x303F
+#define WM8915_WRITE_SEQUENCER_64               0x3040
+#define WM8915_WRITE_SEQUENCER_65               0x3041
+#define WM8915_WRITE_SEQUENCER_66               0x3042
+#define WM8915_WRITE_SEQUENCER_67               0x3043
+#define WM8915_WRITE_SEQUENCER_68               0x3044
+#define WM8915_WRITE_SEQUENCER_69               0x3045
+#define WM8915_WRITE_SEQUENCER_70               0x3046
+#define WM8915_WRITE_SEQUENCER_71               0x3047
+#define WM8915_WRITE_SEQUENCER_72               0x3048
+#define WM8915_WRITE_SEQUENCER_73               0x3049
+#define WM8915_WRITE_SEQUENCER_74               0x304A
+#define WM8915_WRITE_SEQUENCER_75               0x304B
+#define WM8915_WRITE_SEQUENCER_76               0x304C
+#define WM8915_WRITE_SEQUENCER_77               0x304D
+#define WM8915_WRITE_SEQUENCER_78               0x304E
+#define WM8915_WRITE_SEQUENCER_79               0x304F
+#define WM8915_WRITE_SEQUENCER_80               0x3050
+#define WM8915_WRITE_SEQUENCER_81               0x3051
+#define WM8915_WRITE_SEQUENCER_82               0x3052
+#define WM8915_WRITE_SEQUENCER_83               0x3053
+#define WM8915_WRITE_SEQUENCER_84               0x3054
+#define WM8915_WRITE_SEQUENCER_85               0x3055
+#define WM8915_WRITE_SEQUENCER_86               0x3056
+#define WM8915_WRITE_SEQUENCER_87               0x3057
+#define WM8915_WRITE_SEQUENCER_88               0x3058
+#define WM8915_WRITE_SEQUENCER_89               0x3059
+#define WM8915_WRITE_SEQUENCER_90               0x305A
+#define WM8915_WRITE_SEQUENCER_91               0x305B
+#define WM8915_WRITE_SEQUENCER_92               0x305C
+#define WM8915_WRITE_SEQUENCER_93               0x305D
+#define WM8915_WRITE_SEQUENCER_94               0x305E
+#define WM8915_WRITE_SEQUENCER_95               0x305F
+#define WM8915_WRITE_SEQUENCER_96               0x3060
+#define WM8915_WRITE_SEQUENCER_97               0x3061
+#define WM8915_WRITE_SEQUENCER_98               0x3062
+#define WM8915_WRITE_SEQUENCER_99               0x3063
+#define WM8915_WRITE_SEQUENCER_100              0x3064
+#define WM8915_WRITE_SEQUENCER_101              0x3065
+#define WM8915_WRITE_SEQUENCER_102              0x3066
+#define WM8915_WRITE_SEQUENCER_103              0x3067
+#define WM8915_WRITE_SEQUENCER_104              0x3068
+#define WM8915_WRITE_SEQUENCER_105              0x3069
+#define WM8915_WRITE_SEQUENCER_106              0x306A
+#define WM8915_WRITE_SEQUENCER_107              0x306B
+#define WM8915_WRITE_SEQUENCER_108              0x306C
+#define WM8915_WRITE_SEQUENCER_109              0x306D
+#define WM8915_WRITE_SEQUENCER_110              0x306E
+#define WM8915_WRITE_SEQUENCER_111              0x306F
+#define WM8915_WRITE_SEQUENCER_112              0x3070
+#define WM8915_WRITE_SEQUENCER_113              0x3071
+#define WM8915_WRITE_SEQUENCER_114              0x3072
+#define WM8915_WRITE_SEQUENCER_115              0x3073
+#define WM8915_WRITE_SEQUENCER_116              0x3074
+#define WM8915_WRITE_SEQUENCER_117              0x3075
+#define WM8915_WRITE_SEQUENCER_118              0x3076
+#define WM8915_WRITE_SEQUENCER_119              0x3077
+#define WM8915_WRITE_SEQUENCER_120              0x3078
+#define WM8915_WRITE_SEQUENCER_121              0x3079
+#define WM8915_WRITE_SEQUENCER_122              0x307A
+#define WM8915_WRITE_SEQUENCER_123              0x307B
+#define WM8915_WRITE_SEQUENCER_124              0x307C
+#define WM8915_WRITE_SEQUENCER_125              0x307D
+#define WM8915_WRITE_SEQUENCER_126              0x307E
+#define WM8915_WRITE_SEQUENCER_127              0x307F
+#define WM8915_WRITE_SEQUENCER_128              0x3080
+#define WM8915_WRITE_SEQUENCER_129              0x3081
+#define WM8915_WRITE_SEQUENCER_130              0x3082
+#define WM8915_WRITE_SEQUENCER_131              0x3083
+#define WM8915_WRITE_SEQUENCER_132              0x3084
+#define WM8915_WRITE_SEQUENCER_133              0x3085
+#define WM8915_WRITE_SEQUENCER_134              0x3086
+#define WM8915_WRITE_SEQUENCER_135              0x3087
+#define WM8915_WRITE_SEQUENCER_136              0x3088
+#define WM8915_WRITE_SEQUENCER_137              0x3089
+#define WM8915_WRITE_SEQUENCER_138              0x308A
+#define WM8915_WRITE_SEQUENCER_139              0x308B
+#define WM8915_WRITE_SEQUENCER_140              0x308C
+#define WM8915_WRITE_SEQUENCER_141              0x308D
+#define WM8915_WRITE_SEQUENCER_142              0x308E
+#define WM8915_WRITE_SEQUENCER_143              0x308F
+#define WM8915_WRITE_SEQUENCER_144              0x3090
+#define WM8915_WRITE_SEQUENCER_145              0x3091
+#define WM8915_WRITE_SEQUENCER_146              0x3092
+#define WM8915_WRITE_SEQUENCER_147              0x3093
+#define WM8915_WRITE_SEQUENCER_148              0x3094
+#define WM8915_WRITE_SEQUENCER_149              0x3095
+#define WM8915_WRITE_SEQUENCER_150              0x3096
+#define WM8915_WRITE_SEQUENCER_151              0x3097
+#define WM8915_WRITE_SEQUENCER_152              0x3098
+#define WM8915_WRITE_SEQUENCER_153              0x3099
+#define WM8915_WRITE_SEQUENCER_154              0x309A
+#define WM8915_WRITE_SEQUENCER_155              0x309B
+#define WM8915_WRITE_SEQUENCER_156              0x309C
+#define WM8915_WRITE_SEQUENCER_157              0x309D
+#define WM8915_WRITE_SEQUENCER_158              0x309E
+#define WM8915_WRITE_SEQUENCER_159              0x309F
+#define WM8915_WRITE_SEQUENCER_160              0x30A0
+#define WM8915_WRITE_SEQUENCER_161              0x30A1
+#define WM8915_WRITE_SEQUENCER_162              0x30A2
+#define WM8915_WRITE_SEQUENCER_163              0x30A3
+#define WM8915_WRITE_SEQUENCER_164              0x30A4
+#define WM8915_WRITE_SEQUENCER_165              0x30A5
+#define WM8915_WRITE_SEQUENCER_166              0x30A6
+#define WM8915_WRITE_SEQUENCER_167              0x30A7
+#define WM8915_WRITE_SEQUENCER_168              0x30A8
+#define WM8915_WRITE_SEQUENCER_169              0x30A9
+#define WM8915_WRITE_SEQUENCER_170              0x30AA
+#define WM8915_WRITE_SEQUENCER_171              0x30AB
+#define WM8915_WRITE_SEQUENCER_172              0x30AC
+#define WM8915_WRITE_SEQUENCER_173              0x30AD
+#define WM8915_WRITE_SEQUENCER_174              0x30AE
+#define WM8915_WRITE_SEQUENCER_175              0x30AF
+#define WM8915_WRITE_SEQUENCER_176              0x30B0
+#define WM8915_WRITE_SEQUENCER_177              0x30B1
+#define WM8915_WRITE_SEQUENCER_178              0x30B2
+#define WM8915_WRITE_SEQUENCER_179              0x30B3
+#define WM8915_WRITE_SEQUENCER_180              0x30B4
+#define WM8915_WRITE_SEQUENCER_181              0x30B5
+#define WM8915_WRITE_SEQUENCER_182              0x30B6
+#define WM8915_WRITE_SEQUENCER_183              0x30B7
+#define WM8915_WRITE_SEQUENCER_184              0x30B8
+#define WM8915_WRITE_SEQUENCER_185              0x30B9
+#define WM8915_WRITE_SEQUENCER_186              0x30BA
+#define WM8915_WRITE_SEQUENCER_187              0x30BB
+#define WM8915_WRITE_SEQUENCER_188              0x30BC
+#define WM8915_WRITE_SEQUENCER_189              0x30BD
+#define WM8915_WRITE_SEQUENCER_190              0x30BE
+#define WM8915_WRITE_SEQUENCER_191              0x30BF
+#define WM8915_WRITE_SEQUENCER_192              0x30C0
+#define WM8915_WRITE_SEQUENCER_193              0x30C1
+#define WM8915_WRITE_SEQUENCER_194              0x30C2
+#define WM8915_WRITE_SEQUENCER_195              0x30C3
+#define WM8915_WRITE_SEQUENCER_196              0x30C4
+#define WM8915_WRITE_SEQUENCER_197              0x30C5
+#define WM8915_WRITE_SEQUENCER_198              0x30C6
+#define WM8915_WRITE_SEQUENCER_199              0x30C7
+#define WM8915_WRITE_SEQUENCER_200              0x30C8
+#define WM8915_WRITE_SEQUENCER_201              0x30C9
+#define WM8915_WRITE_SEQUENCER_202              0x30CA
+#define WM8915_WRITE_SEQUENCER_203              0x30CB
+#define WM8915_WRITE_SEQUENCER_204              0x30CC
+#define WM8915_WRITE_SEQUENCER_205              0x30CD
+#define WM8915_WRITE_SEQUENCER_206              0x30CE
+#define WM8915_WRITE_SEQUENCER_207              0x30CF
+#define WM8915_WRITE_SEQUENCER_208              0x30D0
+#define WM8915_WRITE_SEQUENCER_209              0x30D1
+#define WM8915_WRITE_SEQUENCER_210              0x30D2
+#define WM8915_WRITE_SEQUENCER_211              0x30D3
+#define WM8915_WRITE_SEQUENCER_212              0x30D4
+#define WM8915_WRITE_SEQUENCER_213              0x30D5
+#define WM8915_WRITE_SEQUENCER_214              0x30D6
+#define WM8915_WRITE_SEQUENCER_215              0x30D7
+#define WM8915_WRITE_SEQUENCER_216              0x30D8
+#define WM8915_WRITE_SEQUENCER_217              0x30D9
+#define WM8915_WRITE_SEQUENCER_218              0x30DA
+#define WM8915_WRITE_SEQUENCER_219              0x30DB
+#define WM8915_WRITE_SEQUENCER_220              0x30DC
+#define WM8915_WRITE_SEQUENCER_221              0x30DD
+#define WM8915_WRITE_SEQUENCER_222              0x30DE
+#define WM8915_WRITE_SEQUENCER_223              0x30DF
+#define WM8915_WRITE_SEQUENCER_224              0x30E0
+#define WM8915_WRITE_SEQUENCER_225              0x30E1
+#define WM8915_WRITE_SEQUENCER_226              0x30E2
+#define WM8915_WRITE_SEQUENCER_227              0x30E3
+#define WM8915_WRITE_SEQUENCER_228              0x30E4
+#define WM8915_WRITE_SEQUENCER_229              0x30E5
+#define WM8915_WRITE_SEQUENCER_230              0x30E6
+#define WM8915_WRITE_SEQUENCER_231              0x30E7
+#define WM8915_WRITE_SEQUENCER_232              0x30E8
+#define WM8915_WRITE_SEQUENCER_233              0x30E9
+#define WM8915_WRITE_SEQUENCER_234              0x30EA
+#define WM8915_WRITE_SEQUENCER_235              0x30EB
+#define WM8915_WRITE_SEQUENCER_236              0x30EC
+#define WM8915_WRITE_SEQUENCER_237              0x30ED
+#define WM8915_WRITE_SEQUENCER_238              0x30EE
+#define WM8915_WRITE_SEQUENCER_239              0x30EF
+#define WM8915_WRITE_SEQUENCER_240              0x30F0
+#define WM8915_WRITE_SEQUENCER_241              0x30F1
+#define WM8915_WRITE_SEQUENCER_242              0x30F2
+#define WM8915_WRITE_SEQUENCER_243              0x30F3
+#define WM8915_WRITE_SEQUENCER_244              0x30F4
+#define WM8915_WRITE_SEQUENCER_245              0x30F5
+#define WM8915_WRITE_SEQUENCER_246              0x30F6
+#define WM8915_WRITE_SEQUENCER_247              0x30F7
+#define WM8915_WRITE_SEQUENCER_248              0x30F8
+#define WM8915_WRITE_SEQUENCER_249              0x30F9
+#define WM8915_WRITE_SEQUENCER_250              0x30FA
+#define WM8915_WRITE_SEQUENCER_251              0x30FB
+#define WM8915_WRITE_SEQUENCER_252              0x30FC
+#define WM8915_WRITE_SEQUENCER_253              0x30FD
+#define WM8915_WRITE_SEQUENCER_254              0x30FE
+#define WM8915_WRITE_SEQUENCER_255              0x30FF
+#define WM8915_WRITE_SEQUENCER_256              0x3100
+#define WM8915_WRITE_SEQUENCER_257              0x3101
+#define WM8915_WRITE_SEQUENCER_258              0x3102
+#define WM8915_WRITE_SEQUENCER_259              0x3103
+#define WM8915_WRITE_SEQUENCER_260              0x3104
+#define WM8915_WRITE_SEQUENCER_261              0x3105
+#define WM8915_WRITE_SEQUENCER_262              0x3106
+#define WM8915_WRITE_SEQUENCER_263              0x3107
+#define WM8915_WRITE_SEQUENCER_264              0x3108
+#define WM8915_WRITE_SEQUENCER_265              0x3109
+#define WM8915_WRITE_SEQUENCER_266              0x310A
+#define WM8915_WRITE_SEQUENCER_267              0x310B
+#define WM8915_WRITE_SEQUENCER_268              0x310C
+#define WM8915_WRITE_SEQUENCER_269              0x310D
+#define WM8915_WRITE_SEQUENCER_270              0x310E
+#define WM8915_WRITE_SEQUENCER_271              0x310F
+#define WM8915_WRITE_SEQUENCER_272              0x3110
+#define WM8915_WRITE_SEQUENCER_273              0x3111
+#define WM8915_WRITE_SEQUENCER_274              0x3112
+#define WM8915_WRITE_SEQUENCER_275              0x3113
+#define WM8915_WRITE_SEQUENCER_276              0x3114
+#define WM8915_WRITE_SEQUENCER_277              0x3115
+#define WM8915_WRITE_SEQUENCER_278              0x3116
+#define WM8915_WRITE_SEQUENCER_279              0x3117
+#define WM8915_WRITE_SEQUENCER_280              0x3118
+#define WM8915_WRITE_SEQUENCER_281              0x3119
+#define WM8915_WRITE_SEQUENCER_282              0x311A
+#define WM8915_WRITE_SEQUENCER_283              0x311B
+#define WM8915_WRITE_SEQUENCER_284              0x311C
+#define WM8915_WRITE_SEQUENCER_285              0x311D
+#define WM8915_WRITE_SEQUENCER_286              0x311E
+#define WM8915_WRITE_SEQUENCER_287              0x311F
+#define WM8915_WRITE_SEQUENCER_288              0x3120
+#define WM8915_WRITE_SEQUENCER_289              0x3121
+#define WM8915_WRITE_SEQUENCER_290              0x3122
+#define WM8915_WRITE_SEQUENCER_291              0x3123
+#define WM8915_WRITE_SEQUENCER_292              0x3124
+#define WM8915_WRITE_SEQUENCER_293              0x3125
+#define WM8915_WRITE_SEQUENCER_294              0x3126
+#define WM8915_WRITE_SEQUENCER_295              0x3127
+#define WM8915_WRITE_SEQUENCER_296              0x3128
+#define WM8915_WRITE_SEQUENCER_297              0x3129
+#define WM8915_WRITE_SEQUENCER_298              0x312A
+#define WM8915_WRITE_SEQUENCER_299              0x312B
+#define WM8915_WRITE_SEQUENCER_300              0x312C
+#define WM8915_WRITE_SEQUENCER_301              0x312D
+#define WM8915_WRITE_SEQUENCER_302              0x312E
+#define WM8915_WRITE_SEQUENCER_303              0x312F
+#define WM8915_WRITE_SEQUENCER_304              0x3130
+#define WM8915_WRITE_SEQUENCER_305              0x3131
+#define WM8915_WRITE_SEQUENCER_306              0x3132
+#define WM8915_WRITE_SEQUENCER_307              0x3133
+#define WM8915_WRITE_SEQUENCER_308              0x3134
+#define WM8915_WRITE_SEQUENCER_309              0x3135
+#define WM8915_WRITE_SEQUENCER_310              0x3136
+#define WM8915_WRITE_SEQUENCER_311              0x3137
+#define WM8915_WRITE_SEQUENCER_312              0x3138
+#define WM8915_WRITE_SEQUENCER_313              0x3139
+#define WM8915_WRITE_SEQUENCER_314              0x313A
+#define WM8915_WRITE_SEQUENCER_315              0x313B
+#define WM8915_WRITE_SEQUENCER_316              0x313C
+#define WM8915_WRITE_SEQUENCER_317              0x313D
+#define WM8915_WRITE_SEQUENCER_318              0x313E
+#define WM8915_WRITE_SEQUENCER_319              0x313F
+#define WM8915_WRITE_SEQUENCER_320              0x3140
+#define WM8915_WRITE_SEQUENCER_321              0x3141
+#define WM8915_WRITE_SEQUENCER_322              0x3142
+#define WM8915_WRITE_SEQUENCER_323              0x3143
+#define WM8915_WRITE_SEQUENCER_324              0x3144
+#define WM8915_WRITE_SEQUENCER_325              0x3145
+#define WM8915_WRITE_SEQUENCER_326              0x3146
+#define WM8915_WRITE_SEQUENCER_327              0x3147
+#define WM8915_WRITE_SEQUENCER_328              0x3148
+#define WM8915_WRITE_SEQUENCER_329              0x3149
+#define WM8915_WRITE_SEQUENCER_330              0x314A
+#define WM8915_WRITE_SEQUENCER_331              0x314B
+#define WM8915_WRITE_SEQUENCER_332              0x314C
+#define WM8915_WRITE_SEQUENCER_333              0x314D
+#define WM8915_WRITE_SEQUENCER_334              0x314E
+#define WM8915_WRITE_SEQUENCER_335              0x314F
+#define WM8915_WRITE_SEQUENCER_336              0x3150
+#define WM8915_WRITE_SEQUENCER_337              0x3151
+#define WM8915_WRITE_SEQUENCER_338              0x3152
+#define WM8915_WRITE_SEQUENCER_339              0x3153
+#define WM8915_WRITE_SEQUENCER_340              0x3154
+#define WM8915_WRITE_SEQUENCER_341              0x3155
+#define WM8915_WRITE_SEQUENCER_342              0x3156
+#define WM8915_WRITE_SEQUENCER_343              0x3157
+#define WM8915_WRITE_SEQUENCER_344              0x3158
+#define WM8915_WRITE_SEQUENCER_345              0x3159
+#define WM8915_WRITE_SEQUENCER_346              0x315A
+#define WM8915_WRITE_SEQUENCER_347              0x315B
+#define WM8915_WRITE_SEQUENCER_348              0x315C
+#define WM8915_WRITE_SEQUENCER_349              0x315D
+#define WM8915_WRITE_SEQUENCER_350              0x315E
+#define WM8915_WRITE_SEQUENCER_351              0x315F
+#define WM8915_WRITE_SEQUENCER_352              0x3160
+#define WM8915_WRITE_SEQUENCER_353              0x3161
+#define WM8915_WRITE_SEQUENCER_354              0x3162
+#define WM8915_WRITE_SEQUENCER_355              0x3163
+#define WM8915_WRITE_SEQUENCER_356              0x3164
+#define WM8915_WRITE_SEQUENCER_357              0x3165
+#define WM8915_WRITE_SEQUENCER_358              0x3166
+#define WM8915_WRITE_SEQUENCER_359              0x3167
+#define WM8915_WRITE_SEQUENCER_360              0x3168
+#define WM8915_WRITE_SEQUENCER_361              0x3169
+#define WM8915_WRITE_SEQUENCER_362              0x316A
+#define WM8915_WRITE_SEQUENCER_363              0x316B
+#define WM8915_WRITE_SEQUENCER_364              0x316C
+#define WM8915_WRITE_SEQUENCER_365              0x316D
+#define WM8915_WRITE_SEQUENCER_366              0x316E
+#define WM8915_WRITE_SEQUENCER_367              0x316F
+#define WM8915_WRITE_SEQUENCER_368              0x3170
+#define WM8915_WRITE_SEQUENCER_369              0x3171
+#define WM8915_WRITE_SEQUENCER_370              0x3172
+#define WM8915_WRITE_SEQUENCER_371              0x3173
+#define WM8915_WRITE_SEQUENCER_372              0x3174
+#define WM8915_WRITE_SEQUENCER_373              0x3175
+#define WM8915_WRITE_SEQUENCER_374              0x3176
+#define WM8915_WRITE_SEQUENCER_375              0x3177
+#define WM8915_WRITE_SEQUENCER_376              0x3178
+#define WM8915_WRITE_SEQUENCER_377              0x3179
+#define WM8915_WRITE_SEQUENCER_378              0x317A
+#define WM8915_WRITE_SEQUENCER_379              0x317B
+#define WM8915_WRITE_SEQUENCER_380              0x317C
+#define WM8915_WRITE_SEQUENCER_381              0x317D
+#define WM8915_WRITE_SEQUENCER_382              0x317E
+#define WM8915_WRITE_SEQUENCER_383              0x317F
+#define WM8915_WRITE_SEQUENCER_384              0x3180
+#define WM8915_WRITE_SEQUENCER_385              0x3181
+#define WM8915_WRITE_SEQUENCER_386              0x3182
+#define WM8915_WRITE_SEQUENCER_387              0x3183
+#define WM8915_WRITE_SEQUENCER_388              0x3184
+#define WM8915_WRITE_SEQUENCER_389              0x3185
+#define WM8915_WRITE_SEQUENCER_390              0x3186
+#define WM8915_WRITE_SEQUENCER_391              0x3187
+#define WM8915_WRITE_SEQUENCER_392              0x3188
+#define WM8915_WRITE_SEQUENCER_393              0x3189
+#define WM8915_WRITE_SEQUENCER_394              0x318A
+#define WM8915_WRITE_SEQUENCER_395              0x318B
+#define WM8915_WRITE_SEQUENCER_396              0x318C
+#define WM8915_WRITE_SEQUENCER_397              0x318D
+#define WM8915_WRITE_SEQUENCER_398              0x318E
+#define WM8915_WRITE_SEQUENCER_399              0x318F
+#define WM8915_WRITE_SEQUENCER_400              0x3190
+#define WM8915_WRITE_SEQUENCER_401              0x3191
+#define WM8915_WRITE_SEQUENCER_402              0x3192
+#define WM8915_WRITE_SEQUENCER_403              0x3193
+#define WM8915_WRITE_SEQUENCER_404              0x3194
+#define WM8915_WRITE_SEQUENCER_405              0x3195
+#define WM8915_WRITE_SEQUENCER_406              0x3196
+#define WM8915_WRITE_SEQUENCER_407              0x3197
+#define WM8915_WRITE_SEQUENCER_408              0x3198
+#define WM8915_WRITE_SEQUENCER_409              0x3199
+#define WM8915_WRITE_SEQUENCER_410              0x319A
+#define WM8915_WRITE_SEQUENCER_411              0x319B
+#define WM8915_WRITE_SEQUENCER_412              0x319C
+#define WM8915_WRITE_SEQUENCER_413              0x319D
+#define WM8915_WRITE_SEQUENCER_414              0x319E
+#define WM8915_WRITE_SEQUENCER_415              0x319F
+#define WM8915_WRITE_SEQUENCER_416              0x31A0
+#define WM8915_WRITE_SEQUENCER_417              0x31A1
+#define WM8915_WRITE_SEQUENCER_418              0x31A2
+#define WM8915_WRITE_SEQUENCER_419              0x31A3
+#define WM8915_WRITE_SEQUENCER_420              0x31A4
+#define WM8915_WRITE_SEQUENCER_421              0x31A5
+#define WM8915_WRITE_SEQUENCER_422              0x31A6
+#define WM8915_WRITE_SEQUENCER_423              0x31A7
+#define WM8915_WRITE_SEQUENCER_424              0x31A8
+#define WM8915_WRITE_SEQUENCER_425              0x31A9
+#define WM8915_WRITE_SEQUENCER_426              0x31AA
+#define WM8915_WRITE_SEQUENCER_427              0x31AB
+#define WM8915_WRITE_SEQUENCER_428              0x31AC
+#define WM8915_WRITE_SEQUENCER_429              0x31AD
+#define WM8915_WRITE_SEQUENCER_430              0x31AE
+#define WM8915_WRITE_SEQUENCER_431              0x31AF
+#define WM8915_WRITE_SEQUENCER_432              0x31B0
+#define WM8915_WRITE_SEQUENCER_433              0x31B1
+#define WM8915_WRITE_SEQUENCER_434              0x31B2
+#define WM8915_WRITE_SEQUENCER_435              0x31B3
+#define WM8915_WRITE_SEQUENCER_436              0x31B4
+#define WM8915_WRITE_SEQUENCER_437              0x31B5
+#define WM8915_WRITE_SEQUENCER_438              0x31B6
+#define WM8915_WRITE_SEQUENCER_439              0x31B7
+#define WM8915_WRITE_SEQUENCER_440              0x31B8
+#define WM8915_WRITE_SEQUENCER_441              0x31B9
+#define WM8915_WRITE_SEQUENCER_442              0x31BA
+#define WM8915_WRITE_SEQUENCER_443              0x31BB
+#define WM8915_WRITE_SEQUENCER_444              0x31BC
+#define WM8915_WRITE_SEQUENCER_445              0x31BD
+#define WM8915_WRITE_SEQUENCER_446              0x31BE
+#define WM8915_WRITE_SEQUENCER_447              0x31BF
+#define WM8915_WRITE_SEQUENCER_448              0x31C0
+#define WM8915_WRITE_SEQUENCER_449              0x31C1
+#define WM8915_WRITE_SEQUENCER_450              0x31C2
+#define WM8915_WRITE_SEQUENCER_451              0x31C3
+#define WM8915_WRITE_SEQUENCER_452              0x31C4
+#define WM8915_WRITE_SEQUENCER_453              0x31C5
+#define WM8915_WRITE_SEQUENCER_454              0x31C6
+#define WM8915_WRITE_SEQUENCER_455              0x31C7
+#define WM8915_WRITE_SEQUENCER_456              0x31C8
+#define WM8915_WRITE_SEQUENCER_457              0x31C9
+#define WM8915_WRITE_SEQUENCER_458              0x31CA
+#define WM8915_WRITE_SEQUENCER_459              0x31CB
+#define WM8915_WRITE_SEQUENCER_460              0x31CC
+#define WM8915_WRITE_SEQUENCER_461              0x31CD
+#define WM8915_WRITE_SEQUENCER_462              0x31CE
+#define WM8915_WRITE_SEQUENCER_463              0x31CF
+#define WM8915_WRITE_SEQUENCER_464              0x31D0
+#define WM8915_WRITE_SEQUENCER_465              0x31D1
+#define WM8915_WRITE_SEQUENCER_466              0x31D2
+#define WM8915_WRITE_SEQUENCER_467              0x31D3
+#define WM8915_WRITE_SEQUENCER_468              0x31D4
+#define WM8915_WRITE_SEQUENCER_469              0x31D5
+#define WM8915_WRITE_SEQUENCER_470              0x31D6
+#define WM8915_WRITE_SEQUENCER_471              0x31D7
+#define WM8915_WRITE_SEQUENCER_472              0x31D8
+#define WM8915_WRITE_SEQUENCER_473              0x31D9
+#define WM8915_WRITE_SEQUENCER_474              0x31DA
+#define WM8915_WRITE_SEQUENCER_475              0x31DB
+#define WM8915_WRITE_SEQUENCER_476              0x31DC
+#define WM8915_WRITE_SEQUENCER_477              0x31DD
+#define WM8915_WRITE_SEQUENCER_478              0x31DE
+#define WM8915_WRITE_SEQUENCER_479              0x31DF
+#define WM8915_WRITE_SEQUENCER_480              0x31E0
+#define WM8915_WRITE_SEQUENCER_481              0x31E1
+#define WM8915_WRITE_SEQUENCER_482              0x31E2
+#define WM8915_WRITE_SEQUENCER_483              0x31E3
+#define WM8915_WRITE_SEQUENCER_484              0x31E4
+#define WM8915_WRITE_SEQUENCER_485              0x31E5
+#define WM8915_WRITE_SEQUENCER_486              0x31E6
+#define WM8915_WRITE_SEQUENCER_487              0x31E7
+#define WM8915_WRITE_SEQUENCER_488              0x31E8
+#define WM8915_WRITE_SEQUENCER_489              0x31E9
+#define WM8915_WRITE_SEQUENCER_490              0x31EA
+#define WM8915_WRITE_SEQUENCER_491              0x31EB
+#define WM8915_WRITE_SEQUENCER_492              0x31EC
+#define WM8915_WRITE_SEQUENCER_493              0x31ED
+#define WM8915_WRITE_SEQUENCER_494              0x31EE
+#define WM8915_WRITE_SEQUENCER_495              0x31EF
+#define WM8915_WRITE_SEQUENCER_496              0x31F0
+#define WM8915_WRITE_SEQUENCER_497              0x31F1
+#define WM8915_WRITE_SEQUENCER_498              0x31F2
+#define WM8915_WRITE_SEQUENCER_499              0x31F3
+#define WM8915_WRITE_SEQUENCER_500              0x31F4
+#define WM8915_WRITE_SEQUENCER_501              0x31F5
+#define WM8915_WRITE_SEQUENCER_502              0x31F6
+#define WM8915_WRITE_SEQUENCER_503              0x31F7
+#define WM8915_WRITE_SEQUENCER_504              0x31F8
+#define WM8915_WRITE_SEQUENCER_505              0x31F9
+#define WM8915_WRITE_SEQUENCER_506              0x31FA
+#define WM8915_WRITE_SEQUENCER_507              0x31FB
+#define WM8915_WRITE_SEQUENCER_508              0x31FC
+#define WM8915_WRITE_SEQUENCER_509              0x31FD
+#define WM8915_WRITE_SEQUENCER_510              0x31FE
+#define WM8915_WRITE_SEQUENCER_511              0x31FF
+
+#define WM8915_REGISTER_COUNT                   706
+#define WM8915_MAX_REGISTER                     0x31FF
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+#define WM8915_SW_RESET_MASK                    0xFFFF  /* SW_RESET - [15:0] */
+#define WM8915_SW_RESET_SHIFT                        0  /* SW_RESET - [15:0] */
+#define WM8915_SW_RESET_WIDTH                       16  /* SW_RESET - [15:0] */
+
+/*
+ * R1 (0x01) - Power Management (1)
+ */
+#define WM8915_MICB2_ENA                        0x0200  /* MICB2_ENA */
+#define WM8915_MICB2_ENA_MASK                   0x0200  /* MICB2_ENA */
+#define WM8915_MICB2_ENA_SHIFT                       9  /* MICB2_ENA */
+#define WM8915_MICB2_ENA_WIDTH                       1  /* MICB2_ENA */
+#define WM8915_MICB1_ENA                        0x0100  /* MICB1_ENA */
+#define WM8915_MICB1_ENA_MASK                   0x0100  /* MICB1_ENA */
+#define WM8915_MICB1_ENA_SHIFT                       8  /* MICB1_ENA */
+#define WM8915_MICB1_ENA_WIDTH                       1  /* MICB1_ENA */
+#define WM8915_HPOUT2L_ENA                      0x0080  /* HPOUT2L_ENA */
+#define WM8915_HPOUT2L_ENA_MASK                 0x0080  /* HPOUT2L_ENA */
+#define WM8915_HPOUT2L_ENA_SHIFT                     7  /* HPOUT2L_ENA */
+#define WM8915_HPOUT2L_ENA_WIDTH                     1  /* HPOUT2L_ENA */
+#define WM8915_HPOUT2R_ENA                      0x0040  /* HPOUT2R_ENA */
+#define WM8915_HPOUT2R_ENA_MASK                 0x0040  /* HPOUT2R_ENA */
+#define WM8915_HPOUT2R_ENA_SHIFT                     6  /* HPOUT2R_ENA */
+#define WM8915_HPOUT2R_ENA_WIDTH                     1  /* HPOUT2R_ENA */
+#define WM8915_HPOUT1L_ENA                      0x0020  /* HPOUT1L_ENA */
+#define WM8915_HPOUT1L_ENA_MASK                 0x0020  /* HPOUT1L_ENA */
+#define WM8915_HPOUT1L_ENA_SHIFT                     5  /* HPOUT1L_ENA */
+#define WM8915_HPOUT1L_ENA_WIDTH                     1  /* HPOUT1L_ENA */
+#define WM8915_HPOUT1R_ENA                      0x0010  /* HPOUT1R_ENA */
+#define WM8915_HPOUT1R_ENA_MASK                 0x0010  /* HPOUT1R_ENA */
+#define WM8915_HPOUT1R_ENA_SHIFT                     4  /* HPOUT1R_ENA */
+#define WM8915_HPOUT1R_ENA_WIDTH                     1  /* HPOUT1R_ENA */
+#define WM8915_BG_ENA                           0x0001  /* BG_ENA */
+#define WM8915_BG_ENA_MASK                      0x0001  /* BG_ENA */
+#define WM8915_BG_ENA_SHIFT                          0  /* BG_ENA */
+#define WM8915_BG_ENA_WIDTH                          1  /* BG_ENA */
+
+/*
+ * R2 (0x02) - Power Management (2)
+ */
+#define WM8915_OPCLK_ENA                        0x0800  /* OPCLK_ENA */
+#define WM8915_OPCLK_ENA_MASK                   0x0800  /* OPCLK_ENA */
+#define WM8915_OPCLK_ENA_SHIFT                      11  /* OPCLK_ENA */
+#define WM8915_OPCLK_ENA_WIDTH                       1  /* OPCLK_ENA */
+#define WM8915_INL_ENA                          0x0020  /* INL_ENA */
+#define WM8915_INL_ENA_MASK                     0x0020  /* INL_ENA */
+#define WM8915_INL_ENA_SHIFT                         5  /* INL_ENA */
+#define WM8915_INL_ENA_WIDTH                         1  /* INL_ENA */
+#define WM8915_INR_ENA                          0x0010  /* INR_ENA */
+#define WM8915_INR_ENA_MASK                     0x0010  /* INR_ENA */
+#define WM8915_INR_ENA_SHIFT                         4  /* INR_ENA */
+#define WM8915_INR_ENA_WIDTH                         1  /* INR_ENA */
+#define WM8915_LDO2_ENA                         0x0002  /* LDO2_ENA */
+#define WM8915_LDO2_ENA_MASK                    0x0002  /* LDO2_ENA */
+#define WM8915_LDO2_ENA_SHIFT                        1  /* LDO2_ENA */
+#define WM8915_LDO2_ENA_WIDTH                        1  /* LDO2_ENA */
+
+/*
+ * R3 (0x03) - Power Management (3)
+ */
+#define WM8915_DSP2RXL_ENA                      0x0800  /* DSP2RXL_ENA */
+#define WM8915_DSP2RXL_ENA_MASK                 0x0800  /* DSP2RXL_ENA */
+#define WM8915_DSP2RXL_ENA_SHIFT                    11  /* DSP2RXL_ENA */
+#define WM8915_DSP2RXL_ENA_WIDTH                     1  /* DSP2RXL_ENA */
+#define WM8915_DSP2RXR_ENA                      0x0400  /* DSP2RXR_ENA */
+#define WM8915_DSP2RXR_ENA_MASK                 0x0400  /* DSP2RXR_ENA */
+#define WM8915_DSP2RXR_ENA_SHIFT                    10  /* DSP2RXR_ENA */
+#define WM8915_DSP2RXR_ENA_WIDTH                     1  /* DSP2RXR_ENA */
+#define WM8915_DSP1RXL_ENA                      0x0200  /* DSP1RXL_ENA */
+#define WM8915_DSP1RXL_ENA_MASK                 0x0200  /* DSP1RXL_ENA */
+#define WM8915_DSP1RXL_ENA_SHIFT                     9  /* DSP1RXL_ENA */
+#define WM8915_DSP1RXL_ENA_WIDTH                     1  /* DSP1RXL_ENA */
+#define WM8915_DSP1RXR_ENA                      0x0100  /* DSP1RXR_ENA */
+#define WM8915_DSP1RXR_ENA_MASK                 0x0100  /* DSP1RXR_ENA */
+#define WM8915_DSP1RXR_ENA_SHIFT                     8  /* DSP1RXR_ENA */
+#define WM8915_DSP1RXR_ENA_WIDTH                     1  /* DSP1RXR_ENA */
+#define WM8915_DMIC2L_ENA                       0x0020  /* DMIC2L_ENA */
+#define WM8915_DMIC2L_ENA_MASK                  0x0020  /* DMIC2L_ENA */
+#define WM8915_DMIC2L_ENA_SHIFT                      5  /* DMIC2L_ENA */
+#define WM8915_DMIC2L_ENA_WIDTH                      1  /* DMIC2L_ENA */
+#define WM8915_DMIC2R_ENA                       0x0010  /* DMIC2R_ENA */
+#define WM8915_DMIC2R_ENA_MASK                  0x0010  /* DMIC2R_ENA */
+#define WM8915_DMIC2R_ENA_SHIFT                      4  /* DMIC2R_ENA */
+#define WM8915_DMIC2R_ENA_WIDTH                      1  /* DMIC2R_ENA */
+#define WM8915_DMIC1L_ENA                       0x0008  /* DMIC1L_ENA */
+#define WM8915_DMIC1L_ENA_MASK                  0x0008  /* DMIC1L_ENA */
+#define WM8915_DMIC1L_ENA_SHIFT                      3  /* DMIC1L_ENA */
+#define WM8915_DMIC1L_ENA_WIDTH                      1  /* DMIC1L_ENA */
+#define WM8915_DMIC1R_ENA                       0x0004  /* DMIC1R_ENA */
+#define WM8915_DMIC1R_ENA_MASK                  0x0004  /* DMIC1R_ENA */
+#define WM8915_DMIC1R_ENA_SHIFT                      2  /* DMIC1R_ENA */
+#define WM8915_DMIC1R_ENA_WIDTH                      1  /* DMIC1R_ENA */
+#define WM8915_ADCL_ENA                         0x0002  /* ADCL_ENA */
+#define WM8915_ADCL_ENA_MASK                    0x0002  /* ADCL_ENA */
+#define WM8915_ADCL_ENA_SHIFT                        1  /* ADCL_ENA */
+#define WM8915_ADCL_ENA_WIDTH                        1  /* ADCL_ENA */
+#define WM8915_ADCR_ENA                         0x0001  /* ADCR_ENA */
+#define WM8915_ADCR_ENA_MASK                    0x0001  /* ADCR_ENA */
+#define WM8915_ADCR_ENA_SHIFT                        0  /* ADCR_ENA */
+#define WM8915_ADCR_ENA_WIDTH                        1  /* ADCR_ENA */
+
+/*
+ * R4 (0x04) - Power Management (4)
+ */
+#define WM8915_AIF2RX_CHAN1_ENA                 0x0200  /* AIF2RX_CHAN1_ENA */
+#define WM8915_AIF2RX_CHAN1_ENA_MASK            0x0200  /* AIF2RX_CHAN1_ENA */
+#define WM8915_AIF2RX_CHAN1_ENA_SHIFT                9  /* AIF2RX_CHAN1_ENA */
+#define WM8915_AIF2RX_CHAN1_ENA_WIDTH                1  /* AIF2RX_CHAN1_ENA */
+#define WM8915_AIF2RX_CHAN0_ENA                 0x0100  /* AIF2RX_CHAN0_ENA */
+#define WM8915_AIF2RX_CHAN0_ENA_MASK            0x0100  /* AIF2RX_CHAN0_ENA */
+#define WM8915_AIF2RX_CHAN0_ENA_SHIFT                8  /* AIF2RX_CHAN0_ENA */
+#define WM8915_AIF2RX_CHAN0_ENA_WIDTH                1  /* AIF2RX_CHAN0_ENA */
+#define WM8915_AIF1RX_CHAN5_ENA                 0x0020  /* AIF1RX_CHAN5_ENA */
+#define WM8915_AIF1RX_CHAN5_ENA_MASK            0x0020  /* AIF1RX_CHAN5_ENA */
+#define WM8915_AIF1RX_CHAN5_ENA_SHIFT                5  /* AIF1RX_CHAN5_ENA */
+#define WM8915_AIF1RX_CHAN5_ENA_WIDTH                1  /* AIF1RX_CHAN5_ENA */
+#define WM8915_AIF1RX_CHAN4_ENA                 0x0010  /* AIF1RX_CHAN4_ENA */
+#define WM8915_AIF1RX_CHAN4_ENA_MASK            0x0010  /* AIF1RX_CHAN4_ENA */
+#define WM8915_AIF1RX_CHAN4_ENA_SHIFT                4  /* AIF1RX_CHAN4_ENA */
+#define WM8915_AIF1RX_CHAN4_ENA_WIDTH                1  /* AIF1RX_CHAN4_ENA */
+#define WM8915_AIF1RX_CHAN3_ENA                 0x0008  /* AIF1RX_CHAN3_ENA */
+#define WM8915_AIF1RX_CHAN3_ENA_MASK            0x0008  /* AIF1RX_CHAN3_ENA */
+#define WM8915_AIF1RX_CHAN3_ENA_SHIFT                3  /* AIF1RX_CHAN3_ENA */
+#define WM8915_AIF1RX_CHAN3_ENA_WIDTH                1  /* AIF1RX_CHAN3_ENA */
+#define WM8915_AIF1RX_CHAN2_ENA                 0x0004  /* AIF1RX_CHAN2_ENA */
+#define WM8915_AIF1RX_CHAN2_ENA_MASK            0x0004  /* AIF1RX_CHAN2_ENA */
+#define WM8915_AIF1RX_CHAN2_ENA_SHIFT                2  /* AIF1RX_CHAN2_ENA */
+#define WM8915_AIF1RX_CHAN2_ENA_WIDTH                1  /* AIF1RX_CHAN2_ENA */
+#define WM8915_AIF1RX_CHAN1_ENA                 0x0002  /* AIF1RX_CHAN1_ENA */
+#define WM8915_AIF1RX_CHAN1_ENA_MASK            0x0002  /* AIF1RX_CHAN1_ENA */
+#define WM8915_AIF1RX_CHAN1_ENA_SHIFT                1  /* AIF1RX_CHAN1_ENA */
+#define WM8915_AIF1RX_CHAN1_ENA_WIDTH                1  /* AIF1RX_CHAN1_ENA */
+#define WM8915_AIF1RX_CHAN0_ENA                 0x0001  /* AIF1RX_CHAN0_ENA */
+#define WM8915_AIF1RX_CHAN0_ENA_MASK            0x0001  /* AIF1RX_CHAN0_ENA */
+#define WM8915_AIF1RX_CHAN0_ENA_SHIFT                0  /* AIF1RX_CHAN0_ENA */
+#define WM8915_AIF1RX_CHAN0_ENA_WIDTH                1  /* AIF1RX_CHAN0_ENA */
+
+/*
+ * R5 (0x05) - Power Management (5)
+ */
+#define WM8915_DSP2TXL_ENA                      0x0800  /* DSP2TXL_ENA */
+#define WM8915_DSP2TXL_ENA_MASK                 0x0800  /* DSP2TXL_ENA */
+#define WM8915_DSP2TXL_ENA_SHIFT                    11  /* DSP2TXL_ENA */
+#define WM8915_DSP2TXL_ENA_WIDTH                     1  /* DSP2TXL_ENA */
+#define WM8915_DSP2TXR_ENA                      0x0400  /* DSP2TXR_ENA */
+#define WM8915_DSP2TXR_ENA_MASK                 0x0400  /* DSP2TXR_ENA */
+#define WM8915_DSP2TXR_ENA_SHIFT                    10  /* DSP2TXR_ENA */
+#define WM8915_DSP2TXR_ENA_WIDTH                     1  /* DSP2TXR_ENA */
+#define WM8915_DSP1TXL_ENA                      0x0200  /* DSP1TXL_ENA */
+#define WM8915_DSP1TXL_ENA_MASK                 0x0200  /* DSP1TXL_ENA */
+#define WM8915_DSP1TXL_ENA_SHIFT                     9  /* DSP1TXL_ENA */
+#define WM8915_DSP1TXL_ENA_WIDTH                     1  /* DSP1TXL_ENA */
+#define WM8915_DSP1TXR_ENA                      0x0100  /* DSP1TXR_ENA */
+#define WM8915_DSP1TXR_ENA_MASK                 0x0100  /* DSP1TXR_ENA */
+#define WM8915_DSP1TXR_ENA_SHIFT                     8  /* DSP1TXR_ENA */
+#define WM8915_DSP1TXR_ENA_WIDTH                     1  /* DSP1TXR_ENA */
+#define WM8915_DAC2L_ENA                        0x0008  /* DAC2L_ENA */
+#define WM8915_DAC2L_ENA_MASK                   0x0008  /* DAC2L_ENA */
+#define WM8915_DAC2L_ENA_SHIFT                       3  /* DAC2L_ENA */
+#define WM8915_DAC2L_ENA_WIDTH                       1  /* DAC2L_ENA */
+#define WM8915_DAC2R_ENA                        0x0004  /* DAC2R_ENA */
+#define WM8915_DAC2R_ENA_MASK                   0x0004  /* DAC2R_ENA */
+#define WM8915_DAC2R_ENA_SHIFT                       2  /* DAC2R_ENA */
+#define WM8915_DAC2R_ENA_WIDTH                       1  /* DAC2R_ENA */
+#define WM8915_DAC1L_ENA                        0x0002  /* DAC1L_ENA */
+#define WM8915_DAC1L_ENA_MASK                   0x0002  /* DAC1L_ENA */
+#define WM8915_DAC1L_ENA_SHIFT                       1  /* DAC1L_ENA */
+#define WM8915_DAC1L_ENA_WIDTH                       1  /* DAC1L_ENA */
+#define WM8915_DAC1R_ENA                        0x0001  /* DAC1R_ENA */
+#define WM8915_DAC1R_ENA_MASK                   0x0001  /* DAC1R_ENA */
+#define WM8915_DAC1R_ENA_SHIFT                       0  /* DAC1R_ENA */
+#define WM8915_DAC1R_ENA_WIDTH                       1  /* DAC1R_ENA */
+
+/*
+ * R6 (0x06) - Power Management (6)
+ */
+#define WM8915_AIF2TX_CHAN1_ENA                 0x0200  /* AIF2TX_CHAN1_ENA */
+#define WM8915_AIF2TX_CHAN1_ENA_MASK            0x0200  /* AIF2TX_CHAN1_ENA */
+#define WM8915_AIF2TX_CHAN1_ENA_SHIFT                9  /* AIF2TX_CHAN1_ENA */
+#define WM8915_AIF2TX_CHAN1_ENA_WIDTH                1  /* AIF2TX_CHAN1_ENA */
+#define WM8915_AIF2TX_CHAN0_ENA                 0x0100  /* AIF2TX_CHAN0_ENA */
+#define WM8915_AIF2TX_CHAN0_ENA_MASK            0x0100  /* AIF2TX_CHAN0_ENA */
+#define WM8915_AIF2TX_CHAN0_ENA_SHIFT                8  /* AIF2TX_CHAN0_ENA */
+#define WM8915_AIF2TX_CHAN0_ENA_WIDTH                1  /* AIF2TX_CHAN0_ENA */
+#define WM8915_AIF1TX_CHAN5_ENA                 0x0020  /* AIF1TX_CHAN5_ENA */
+#define WM8915_AIF1TX_CHAN5_ENA_MASK            0x0020  /* AIF1TX_CHAN5_ENA */
+#define WM8915_AIF1TX_CHAN5_ENA_SHIFT                5  /* AIF1TX_CHAN5_ENA */
+#define WM8915_AIF1TX_CHAN5_ENA_WIDTH                1  /* AIF1TX_CHAN5_ENA */
+#define WM8915_AIF1TX_CHAN4_ENA                 0x0010  /* AIF1TX_CHAN4_ENA */
+#define WM8915_AIF1TX_CHAN4_ENA_MASK            0x0010  /* AIF1TX_CHAN4_ENA */
+#define WM8915_AIF1TX_CHAN4_ENA_SHIFT                4  /* AIF1TX_CHAN4_ENA */
+#define WM8915_AIF1TX_CHAN4_ENA_WIDTH                1  /* AIF1TX_CHAN4_ENA */
+#define WM8915_AIF1TX_CHAN3_ENA                 0x0008  /* AIF1TX_CHAN3_ENA */
+#define WM8915_AIF1TX_CHAN3_ENA_MASK            0x0008  /* AIF1TX_CHAN3_ENA */
+#define WM8915_AIF1TX_CHAN3_ENA_SHIFT                3  /* AIF1TX_CHAN3_ENA */
+#define WM8915_AIF1TX_CHAN3_ENA_WIDTH                1  /* AIF1TX_CHAN3_ENA */
+#define WM8915_AIF1TX_CHAN2_ENA                 0x0004  /* AIF1TX_CHAN2_ENA */
+#define WM8915_AIF1TX_CHAN2_ENA_MASK            0x0004  /* AIF1TX_CHAN2_ENA */
+#define WM8915_AIF1TX_CHAN2_ENA_SHIFT                2  /* AIF1TX_CHAN2_ENA */
+#define WM8915_AIF1TX_CHAN2_ENA_WIDTH                1  /* AIF1TX_CHAN2_ENA */
+#define WM8915_AIF1TX_CHAN1_ENA                 0x0002  /* AIF1TX_CHAN1_ENA */
+#define WM8915_AIF1TX_CHAN1_ENA_MASK            0x0002  /* AIF1TX_CHAN1_ENA */
+#define WM8915_AIF1TX_CHAN1_ENA_SHIFT                1  /* AIF1TX_CHAN1_ENA */
+#define WM8915_AIF1TX_CHAN1_ENA_WIDTH                1  /* AIF1TX_CHAN1_ENA */
+#define WM8915_AIF1TX_CHAN0_ENA                 0x0001  /* AIF1TX_CHAN0_ENA */
+#define WM8915_AIF1TX_CHAN0_ENA_MASK            0x0001  /* AIF1TX_CHAN0_ENA */
+#define WM8915_AIF1TX_CHAN0_ENA_SHIFT                0  /* AIF1TX_CHAN0_ENA */
+#define WM8915_AIF1TX_CHAN0_ENA_WIDTH                1  /* AIF1TX_CHAN0_ENA */
+
+/*
+ * R7 (0x07) - Power Management (7)
+ */
+#define WM8915_DMIC2_FN                         0x0200  /* DMIC2_FN */
+#define WM8915_DMIC2_FN_MASK                    0x0200  /* DMIC2_FN */
+#define WM8915_DMIC2_FN_SHIFT                        9  /* DMIC2_FN */
+#define WM8915_DMIC2_FN_WIDTH                        1  /* DMIC2_FN */
+#define WM8915_DMIC1_FN                         0x0100  /* DMIC1_FN */
+#define WM8915_DMIC1_FN_MASK                    0x0100  /* DMIC1_FN */
+#define WM8915_DMIC1_FN_SHIFT                        8  /* DMIC1_FN */
+#define WM8915_DMIC1_FN_WIDTH                        1  /* DMIC1_FN */
+#define WM8915_ADC_DMIC_DSP2R_ENA               0x0080  /* ADC_DMIC_DSP2R_ENA */
+#define WM8915_ADC_DMIC_DSP2R_ENA_MASK          0x0080  /* ADC_DMIC_DSP2R_ENA */
+#define WM8915_ADC_DMIC_DSP2R_ENA_SHIFT              7  /* ADC_DMIC_DSP2R_ENA */
+#define WM8915_ADC_DMIC_DSP2R_ENA_WIDTH              1  /* ADC_DMIC_DSP2R_ENA */
+#define WM8915_ADC_DMIC_DSP2L_ENA               0x0040  /* ADC_DMIC_DSP2L_ENA */
+#define WM8915_ADC_DMIC_DSP2L_ENA_MASK          0x0040  /* ADC_DMIC_DSP2L_ENA */
+#define WM8915_ADC_DMIC_DSP2L_ENA_SHIFT              6  /* ADC_DMIC_DSP2L_ENA */
+#define WM8915_ADC_DMIC_DSP2L_ENA_WIDTH              1  /* ADC_DMIC_DSP2L_ENA */
+#define WM8915_ADC_DMIC_SRC2_MASK               0x0030  /* ADC_DMIC_SRC2 - [5:4] */
+#define WM8915_ADC_DMIC_SRC2_SHIFT                   4  /* ADC_DMIC_SRC2 - [5:4] */
+#define WM8915_ADC_DMIC_SRC2_WIDTH                   2  /* ADC_DMIC_SRC2 - [5:4] */
+#define WM8915_ADC_DMIC_DSP1R_ENA               0x0008  /* ADC_DMIC_DSP1R_ENA */
+#define WM8915_ADC_DMIC_DSP1R_ENA_MASK          0x0008  /* ADC_DMIC_DSP1R_ENA */
+#define WM8915_ADC_DMIC_DSP1R_ENA_SHIFT              3  /* ADC_DMIC_DSP1R_ENA */
+#define WM8915_ADC_DMIC_DSP1R_ENA_WIDTH              1  /* ADC_DMIC_DSP1R_ENA */
+#define WM8915_ADC_DMIC_DSP1L_ENA               0x0004  /* ADC_DMIC_DSP1L_ENA */
+#define WM8915_ADC_DMIC_DSP1L_ENA_MASK          0x0004  /* ADC_DMIC_DSP1L_ENA */
+#define WM8915_ADC_DMIC_DSP1L_ENA_SHIFT              2  /* ADC_DMIC_DSP1L_ENA */
+#define WM8915_ADC_DMIC_DSP1L_ENA_WIDTH              1  /* ADC_DMIC_DSP1L_ENA */
+#define WM8915_ADC_DMIC_SRC1_MASK               0x0003  /* ADC_DMIC_SRC1 - [1:0] */
+#define WM8915_ADC_DMIC_SRC1_SHIFT                   0  /* ADC_DMIC_SRC1 - [1:0] */
+#define WM8915_ADC_DMIC_SRC1_WIDTH                   2  /* ADC_DMIC_SRC1 - [1:0] */
+
+/*
+ * R8 (0x08) - Power Management (8)
+ */
+#define WM8915_AIF2TX_SRC_MASK                  0x00C0  /* AIF2TX_SRC - [7:6] */
+#define WM8915_AIF2TX_SRC_SHIFT                      6  /* AIF2TX_SRC - [7:6] */
+#define WM8915_AIF2TX_SRC_WIDTH                      2  /* AIF2TX_SRC - [7:6] */
+#define WM8915_DSP2RX_SRC                       0x0010  /* DSP2RX_SRC */
+#define WM8915_DSP2RX_SRC_MASK                  0x0010  /* DSP2RX_SRC */
+#define WM8915_DSP2RX_SRC_SHIFT                      4  /* DSP2RX_SRC */
+#define WM8915_DSP2RX_SRC_WIDTH                      1  /* DSP2RX_SRC */
+#define WM8915_DSP1RX_SRC                       0x0001  /* DSP1RX_SRC */
+#define WM8915_DSP1RX_SRC_MASK                  0x0001  /* DSP1RX_SRC */
+#define WM8915_DSP1RX_SRC_SHIFT                      0  /* DSP1RX_SRC */
+#define WM8915_DSP1RX_SRC_WIDTH                      1  /* DSP1RX_SRC */
+
+/*
+ * R16 (0x10) - Left Line Input Volume
+ */
+#define WM8915_IN1_VU                           0x0080  /* IN1_VU */
+#define WM8915_IN1_VU_MASK                      0x0080  /* IN1_VU */
+#define WM8915_IN1_VU_SHIFT                          7  /* IN1_VU */
+#define WM8915_IN1_VU_WIDTH                          1  /* IN1_VU */
+#define WM8915_IN1L_ZC                          0x0020  /* IN1L_ZC */
+#define WM8915_IN1L_ZC_MASK                     0x0020  /* IN1L_ZC */
+#define WM8915_IN1L_ZC_SHIFT                         5  /* IN1L_ZC */
+#define WM8915_IN1L_ZC_WIDTH                         1  /* IN1L_ZC */
+#define WM8915_IN1L_VOL_MASK                    0x001F  /* IN1L_VOL - [4:0] */
+#define WM8915_IN1L_VOL_SHIFT                        0  /* IN1L_VOL - [4:0] */
+#define WM8915_IN1L_VOL_WIDTH                        5  /* IN1L_VOL - [4:0] */
+
+/*
+ * R17 (0x11) - Right Line Input Volume
+ */
+#define WM8915_IN1_VU                           0x0080  /* IN1_VU */
+#define WM8915_IN1_VU_MASK                      0x0080  /* IN1_VU */
+#define WM8915_IN1_VU_SHIFT                          7  /* IN1_VU */
+#define WM8915_IN1_VU_WIDTH                          1  /* IN1_VU */
+#define WM8915_IN1R_ZC                          0x0020  /* IN1R_ZC */
+#define WM8915_IN1R_ZC_MASK                     0x0020  /* IN1R_ZC */
+#define WM8915_IN1R_ZC_SHIFT                         5  /* IN1R_ZC */
+#define WM8915_IN1R_ZC_WIDTH                         1  /* IN1R_ZC */
+#define WM8915_IN1R_VOL_MASK                    0x001F  /* IN1R_VOL - [4:0] */
+#define WM8915_IN1R_VOL_SHIFT                        0  /* IN1R_VOL - [4:0] */
+#define WM8915_IN1R_VOL_WIDTH                        5  /* IN1R_VOL - [4:0] */
+
+/*
+ * R18 (0x12) - Line Input Control
+ */
+#define WM8915_INL_MODE_MASK                    0x000C  /* INL_MODE - [3:2] */
+#define WM8915_INL_MODE_SHIFT                        2  /* INL_MODE - [3:2] */
+#define WM8915_INL_MODE_WIDTH                        2  /* INL_MODE - [3:2] */
+#define WM8915_INR_MODE_MASK                    0x0003  /* INR_MODE - [1:0] */
+#define WM8915_INR_MODE_SHIFT                        0  /* INR_MODE - [1:0] */
+#define WM8915_INR_MODE_WIDTH                        2  /* INR_MODE - [1:0] */
+
+/*
+ * R21 (0x15) - DAC1 HPOUT1 Volume
+ */
+#define WM8915_DAC1R_HPOUT1R_VOL_MASK           0x00F0  /* DAC1R_HPOUT1R_VOL - [7:4] */
+#define WM8915_DAC1R_HPOUT1R_VOL_SHIFT               4  /* DAC1R_HPOUT1R_VOL - [7:4] */
+#define WM8915_DAC1R_HPOUT1R_VOL_WIDTH               4  /* DAC1R_HPOUT1R_VOL - [7:4] */
+#define WM8915_DAC1L_HPOUT1L_VOL_MASK           0x000F  /* DAC1L_HPOUT1L_VOL - [3:0] */
+#define WM8915_DAC1L_HPOUT1L_VOL_SHIFT               0  /* DAC1L_HPOUT1L_VOL - [3:0] */
+#define WM8915_DAC1L_HPOUT1L_VOL_WIDTH               4  /* DAC1L_HPOUT1L_VOL - [3:0] */
+
+/*
+ * R22 (0x16) - DAC2 HPOUT2 Volume
+ */
+#define WM8915_DAC2R_HPOUT2R_VOL_MASK           0x00F0  /* DAC2R_HPOUT2R_VOL - [7:4] */
+#define WM8915_DAC2R_HPOUT2R_VOL_SHIFT               4  /* DAC2R_HPOUT2R_VOL - [7:4] */
+#define WM8915_DAC2R_HPOUT2R_VOL_WIDTH               4  /* DAC2R_HPOUT2R_VOL - [7:4] */
+#define WM8915_DAC2L_HPOUT2L_VOL_MASK           0x000F  /* DAC2L_HPOUT2L_VOL - [3:0] */
+#define WM8915_DAC2L_HPOUT2L_VOL_SHIFT               0  /* DAC2L_HPOUT2L_VOL - [3:0] */
+#define WM8915_DAC2L_HPOUT2L_VOL_WIDTH               4  /* DAC2L_HPOUT2L_VOL - [3:0] */
+
+/*
+ * R24 (0x18) - DAC1 Left Volume
+ */
+#define WM8915_DAC1L_MUTE                       0x0200  /* DAC1L_MUTE */
+#define WM8915_DAC1L_MUTE_MASK                  0x0200  /* DAC1L_MUTE */
+#define WM8915_DAC1L_MUTE_SHIFT                      9  /* DAC1L_MUTE */
+#define WM8915_DAC1L_MUTE_WIDTH                      1  /* DAC1L_MUTE */
+#define WM8915_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8915_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8915_DAC1L_VOL_MASK                   0x00FF  /* DAC1L_VOL - [7:0] */
+#define WM8915_DAC1L_VOL_SHIFT                       0  /* DAC1L_VOL - [7:0] */
+#define WM8915_DAC1L_VOL_WIDTH                       8  /* DAC1L_VOL - [7:0] */
+
+/*
+ * R25 (0x19) - DAC1 Right Volume
+ */
+#define WM8915_DAC1R_MUTE                       0x0200  /* DAC1R_MUTE */
+#define WM8915_DAC1R_MUTE_MASK                  0x0200  /* DAC1R_MUTE */
+#define WM8915_DAC1R_MUTE_SHIFT                      9  /* DAC1R_MUTE */
+#define WM8915_DAC1R_MUTE_WIDTH                      1  /* DAC1R_MUTE */
+#define WM8915_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8915_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8915_DAC1R_VOL_MASK                   0x00FF  /* DAC1R_VOL - [7:0] */
+#define WM8915_DAC1R_VOL_SHIFT                       0  /* DAC1R_VOL - [7:0] */
+#define WM8915_DAC1R_VOL_WIDTH                       8  /* DAC1R_VOL - [7:0] */
+
+/*
+ * R26 (0x1A) - DAC2 Left Volume
+ */
+#define WM8915_DAC2L_MUTE                       0x0200  /* DAC2L_MUTE */
+#define WM8915_DAC2L_MUTE_MASK                  0x0200  /* DAC2L_MUTE */
+#define WM8915_DAC2L_MUTE_SHIFT                      9  /* DAC2L_MUTE */
+#define WM8915_DAC2L_MUTE_WIDTH                      1  /* DAC2L_MUTE */
+#define WM8915_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8915_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8915_DAC2L_VOL_MASK                   0x00FF  /* DAC2L_VOL - [7:0] */
+#define WM8915_DAC2L_VOL_SHIFT                       0  /* DAC2L_VOL - [7:0] */
+#define WM8915_DAC2L_VOL_WIDTH                       8  /* DAC2L_VOL - [7:0] */
+
+/*
+ * R27 (0x1B) - DAC2 Right Volume
+ */
+#define WM8915_DAC2R_MUTE                       0x0200  /* DAC2R_MUTE */
+#define WM8915_DAC2R_MUTE_MASK                  0x0200  /* DAC2R_MUTE */
+#define WM8915_DAC2R_MUTE_SHIFT                      9  /* DAC2R_MUTE */
+#define WM8915_DAC2R_MUTE_WIDTH                      1  /* DAC2R_MUTE */
+#define WM8915_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8915_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8915_DAC2R_VOL_MASK                   0x00FF  /* DAC2R_VOL - [7:0] */
+#define WM8915_DAC2R_VOL_SHIFT                       0  /* DAC2R_VOL - [7:0] */
+#define WM8915_DAC2R_VOL_WIDTH                       8  /* DAC2R_VOL - [7:0] */
+
+/*
+ * R28 (0x1C) - Output1 Left Volume
+ */
+#define WM8915_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8915_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8915_HPOUT1L_ZC                       0x0080  /* HPOUT1L_ZC */
+#define WM8915_HPOUT1L_ZC_MASK                  0x0080  /* HPOUT1L_ZC */
+#define WM8915_HPOUT1L_ZC_SHIFT                      7  /* HPOUT1L_ZC */
+#define WM8915_HPOUT1L_ZC_WIDTH                      1  /* HPOUT1L_ZC */
+#define WM8915_HPOUT1L_VOL_MASK                 0x000F  /* HPOUT1L_VOL - [3:0] */
+#define WM8915_HPOUT1L_VOL_SHIFT                     0  /* HPOUT1L_VOL - [3:0] */
+#define WM8915_HPOUT1L_VOL_WIDTH                     4  /* HPOUT1L_VOL - [3:0] */
+
+/*
+ * R29 (0x1D) - Output1 Right Volume
+ */
+#define WM8915_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8915_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8915_HPOUT1R_ZC                       0x0080  /* HPOUT1R_ZC */
+#define WM8915_HPOUT1R_ZC_MASK                  0x0080  /* HPOUT1R_ZC */
+#define WM8915_HPOUT1R_ZC_SHIFT                      7  /* HPOUT1R_ZC */
+#define WM8915_HPOUT1R_ZC_WIDTH                      1  /* HPOUT1R_ZC */
+#define WM8915_HPOUT1R_VOL_MASK                 0x000F  /* HPOUT1R_VOL - [3:0] */
+#define WM8915_HPOUT1R_VOL_SHIFT                     0  /* HPOUT1R_VOL - [3:0] */
+#define WM8915_HPOUT1R_VOL_WIDTH                     4  /* HPOUT1R_VOL - [3:0] */
+
+/*
+ * R30 (0x1E) - Output2 Left Volume
+ */
+#define WM8915_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8915_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8915_HPOUT2L_ZC                       0x0080  /* HPOUT2L_ZC */
+#define WM8915_HPOUT2L_ZC_MASK                  0x0080  /* HPOUT2L_ZC */
+#define WM8915_HPOUT2L_ZC_SHIFT                      7  /* HPOUT2L_ZC */
+#define WM8915_HPOUT2L_ZC_WIDTH                      1  /* HPOUT2L_ZC */
+#define WM8915_HPOUT2L_VOL_MASK                 0x000F  /* HPOUT2L_VOL - [3:0] */
+#define WM8915_HPOUT2L_VOL_SHIFT                     0  /* HPOUT2L_VOL - [3:0] */
+#define WM8915_HPOUT2L_VOL_WIDTH                     4  /* HPOUT2L_VOL - [3:0] */
+
+/*
+ * R31 (0x1F) - Output2 Right Volume
+ */
+#define WM8915_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8915_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8915_HPOUT2R_ZC                       0x0080  /* HPOUT2R_ZC */
+#define WM8915_HPOUT2R_ZC_MASK                  0x0080  /* HPOUT2R_ZC */
+#define WM8915_HPOUT2R_ZC_SHIFT                      7  /* HPOUT2R_ZC */
+#define WM8915_HPOUT2R_ZC_WIDTH                      1  /* HPOUT2R_ZC */
+#define WM8915_HPOUT2R_VOL_MASK                 0x000F  /* HPOUT2R_VOL - [3:0] */
+#define WM8915_HPOUT2R_VOL_SHIFT                     0  /* HPOUT2R_VOL - [3:0] */
+#define WM8915_HPOUT2R_VOL_WIDTH                     4  /* HPOUT2R_VOL - [3:0] */
+
+/*
+ * R32 (0x20) - MICBIAS (1)
+ */
+#define WM8915_MICB1_RATE                       0x0020  /* MICB1_RATE */
+#define WM8915_MICB1_RATE_MASK                  0x0020  /* MICB1_RATE */
+#define WM8915_MICB1_RATE_SHIFT                      5  /* MICB1_RATE */
+#define WM8915_MICB1_RATE_WIDTH                      1  /* MICB1_RATE */
+#define WM8915_MICB1_MODE                       0x0010  /* MICB1_MODE */
+#define WM8915_MICB1_MODE_MASK                  0x0010  /* MICB1_MODE */
+#define WM8915_MICB1_MODE_SHIFT                      4  /* MICB1_MODE */
+#define WM8915_MICB1_MODE_WIDTH                      1  /* MICB1_MODE */
+#define WM8915_MICB1_LVL_MASK                   0x000E  /* MICB1_LVL - [3:1] */
+#define WM8915_MICB1_LVL_SHIFT                       1  /* MICB1_LVL - [3:1] */
+#define WM8915_MICB1_LVL_WIDTH                       3  /* MICB1_LVL - [3:1] */
+#define WM8915_MICB1_DISCH                      0x0001  /* MICB1_DISCH */
+#define WM8915_MICB1_DISCH_MASK                 0x0001  /* MICB1_DISCH */
+#define WM8915_MICB1_DISCH_SHIFT                     0  /* MICB1_DISCH */
+#define WM8915_MICB1_DISCH_WIDTH                     1  /* MICB1_DISCH */
+
+/*
+ * R33 (0x21) - MICBIAS (2)
+ */
+#define WM8915_MICB2_RATE                       0x0020  /* MICB2_RATE */
+#define WM8915_MICB2_RATE_MASK                  0x0020  /* MICB2_RATE */
+#define WM8915_MICB2_RATE_SHIFT                      5  /* MICB2_RATE */
+#define WM8915_MICB2_RATE_WIDTH                      1  /* MICB2_RATE */
+#define WM8915_MICB2_MODE                       0x0010  /* MICB2_MODE */
+#define WM8915_MICB2_MODE_MASK                  0x0010  /* MICB2_MODE */
+#define WM8915_MICB2_MODE_SHIFT                      4  /* MICB2_MODE */
+#define WM8915_MICB2_MODE_WIDTH                      1  /* MICB2_MODE */
+#define WM8915_MICB2_LVL_MASK                   0x000E  /* MICB2_LVL - [3:1] */
+#define WM8915_MICB2_LVL_SHIFT                       1  /* MICB2_LVL - [3:1] */
+#define WM8915_MICB2_LVL_WIDTH                       3  /* MICB2_LVL - [3:1] */
+#define WM8915_MICB2_DISCH                      0x0001  /* MICB2_DISCH */
+#define WM8915_MICB2_DISCH_MASK                 0x0001  /* MICB2_DISCH */
+#define WM8915_MICB2_DISCH_SHIFT                     0  /* MICB2_DISCH */
+#define WM8915_MICB2_DISCH_WIDTH                     1  /* MICB2_DISCH */
+
+/*
+ * R40 (0x28) - LDO 1
+ */
+#define WM8915_LDO1_MODE                        0x0020  /* LDO1_MODE */
+#define WM8915_LDO1_MODE_MASK                   0x0020  /* LDO1_MODE */
+#define WM8915_LDO1_MODE_SHIFT                       5  /* LDO1_MODE */
+#define WM8915_LDO1_MODE_WIDTH                       1  /* LDO1_MODE */
+#define WM8915_LDO1_VSEL_MASK                   0x0006  /* LDO1_VSEL - [2:1] */
+#define WM8915_LDO1_VSEL_SHIFT                       1  /* LDO1_VSEL - [2:1] */
+#define WM8915_LDO1_VSEL_WIDTH                       2  /* LDO1_VSEL - [2:1] */
+#define WM8915_LDO1_DISCH                       0x0001  /* LDO1_DISCH */
+#define WM8915_LDO1_DISCH_MASK                  0x0001  /* LDO1_DISCH */
+#define WM8915_LDO1_DISCH_SHIFT                      0  /* LDO1_DISCH */
+#define WM8915_LDO1_DISCH_WIDTH                      1  /* LDO1_DISCH */
+
+/*
+ * R41 (0x29) - LDO 2
+ */
+#define WM8915_LDO2_MODE                        0x0020  /* LDO2_MODE */
+#define WM8915_LDO2_MODE_MASK                   0x0020  /* LDO2_MODE */
+#define WM8915_LDO2_MODE_SHIFT                       5  /* LDO2_MODE */
+#define WM8915_LDO2_MODE_WIDTH                       1  /* LDO2_MODE */
+#define WM8915_LDO2_VSEL_MASK                   0x001E  /* LDO2_VSEL - [4:1] */
+#define WM8915_LDO2_VSEL_SHIFT                       1  /* LDO2_VSEL - [4:1] */
+#define WM8915_LDO2_VSEL_WIDTH                       4  /* LDO2_VSEL - [4:1] */
+#define WM8915_LDO2_DISCH                       0x0001  /* LDO2_DISCH */
+#define WM8915_LDO2_DISCH_MASK                  0x0001  /* LDO2_DISCH */
+#define WM8915_LDO2_DISCH_SHIFT                      0  /* LDO2_DISCH */
+#define WM8915_LDO2_DISCH_WIDTH                      1  /* LDO2_DISCH */
+
+/*
+ * R48 (0x30) - Accessory Detect Mode 1
+ */
+#define WM8915_JD_MODE_MASK                     0x0003  /* JD_MODE - [1:0] */
+#define WM8915_JD_MODE_SHIFT                         0  /* JD_MODE - [1:0] */
+#define WM8915_JD_MODE_WIDTH                         2  /* JD_MODE - [1:0] */
+
+/*
+ * R49 (0x31) - Accessory Detect Mode 2
+ */
+#define WM8915_HPOUT1FB_SRC                     0x0004  /* HPOUT1FB_SRC */
+#define WM8915_HPOUT1FB_SRC_MASK                0x0004  /* HPOUT1FB_SRC */
+#define WM8915_HPOUT1FB_SRC_SHIFT                    2  /* HPOUT1FB_SRC */
+#define WM8915_HPOUT1FB_SRC_WIDTH                    1  /* HPOUT1FB_SRC */
+#define WM8915_MICD_SRC                         0x0002  /* MICD_SRC */
+#define WM8915_MICD_SRC_MASK                    0x0002  /* MICD_SRC */
+#define WM8915_MICD_SRC_SHIFT                        1  /* MICD_SRC */
+#define WM8915_MICD_SRC_WIDTH                        1  /* MICD_SRC */
+#define WM8915_MICD_BIAS_SRC                    0x0001  /* MICD_BIAS_SRC */
+#define WM8915_MICD_BIAS_SRC_MASK               0x0001  /* MICD_BIAS_SRC */
+#define WM8915_MICD_BIAS_SRC_SHIFT                   0  /* MICD_BIAS_SRC */
+#define WM8915_MICD_BIAS_SRC_WIDTH                   1  /* MICD_BIAS_SRC */
+
+/*
+ * R52 (0x34) - Headphone Detect 1
+ */
+#define WM8915_HP_HOLDTIME_MASK                 0x00E0  /* HP_HOLDTIME - [7:5] */
+#define WM8915_HP_HOLDTIME_SHIFT                     5  /* HP_HOLDTIME - [7:5] */
+#define WM8915_HP_HOLDTIME_WIDTH                     3  /* HP_HOLDTIME - [7:5] */
+#define WM8915_HP_CLK_DIV_MASK                  0x0018  /* HP_CLK_DIV - [4:3] */
+#define WM8915_HP_CLK_DIV_SHIFT                      3  /* HP_CLK_DIV - [4:3] */
+#define WM8915_HP_CLK_DIV_WIDTH                      2  /* HP_CLK_DIV - [4:3] */
+#define WM8915_HP_STEP_SIZE                     0x0002  /* HP_STEP_SIZE */
+#define WM8915_HP_STEP_SIZE_MASK                0x0002  /* HP_STEP_SIZE */
+#define WM8915_HP_STEP_SIZE_SHIFT                    1  /* HP_STEP_SIZE */
+#define WM8915_HP_STEP_SIZE_WIDTH                    1  /* HP_STEP_SIZE */
+#define WM8915_HP_POLL                          0x0001  /* HP_POLL */
+#define WM8915_HP_POLL_MASK                     0x0001  /* HP_POLL */
+#define WM8915_HP_POLL_SHIFT                         0  /* HP_POLL */
+#define WM8915_HP_POLL_WIDTH                         1  /* HP_POLL */
+
+/*
+ * R53 (0x35) - Headphone Detect 2
+ */
+#define WM8915_HP_DONE                          0x0080  /* HP_DONE */
+#define WM8915_HP_DONE_MASK                     0x0080  /* HP_DONE */
+#define WM8915_HP_DONE_SHIFT                         7  /* HP_DONE */
+#define WM8915_HP_DONE_WIDTH                         1  /* HP_DONE */
+#define WM8915_HP_LVL_MASK                      0x007F  /* HP_LVL - [6:0] */
+#define WM8915_HP_LVL_SHIFT                          0  /* HP_LVL - [6:0] */
+#define WM8915_HP_LVL_WIDTH                          7  /* HP_LVL - [6:0] */
+
+/*
+ * R56 (0x38) - Mic Detect 1
+ */
+#define WM8915_MICD_BIAS_STARTTIME_MASK         0xF000  /* MICD_BIAS_STARTTIME - [15:12] */
+#define WM8915_MICD_BIAS_STARTTIME_SHIFT            12  /* MICD_BIAS_STARTTIME - [15:12] */
+#define WM8915_MICD_BIAS_STARTTIME_WIDTH             4  /* MICD_BIAS_STARTTIME - [15:12] */
+#define WM8915_MICD_RATE_MASK                   0x0F00  /* MICD_RATE - [11:8] */
+#define WM8915_MICD_RATE_SHIFT                       8  /* MICD_RATE - [11:8] */
+#define WM8915_MICD_RATE_WIDTH                       4  /* MICD_RATE - [11:8] */
+#define WM8915_MICD_DBTIME                      0x0002  /* MICD_DBTIME */
+#define WM8915_MICD_DBTIME_MASK                 0x0002  /* MICD_DBTIME */
+#define WM8915_MICD_DBTIME_SHIFT                     1  /* MICD_DBTIME */
+#define WM8915_MICD_DBTIME_WIDTH                     1  /* MICD_DBTIME */
+#define WM8915_MICD_ENA                         0x0001  /* MICD_ENA */
+#define WM8915_MICD_ENA_MASK                    0x0001  /* MICD_ENA */
+#define WM8915_MICD_ENA_SHIFT                        0  /* MICD_ENA */
+#define WM8915_MICD_ENA_WIDTH                        1  /* MICD_ENA */
+
+/*
+ * R57 (0x39) - Mic Detect 2
+ */
+#define WM8915_MICD_LVL_SEL_MASK                0x00FF  /* MICD_LVL_SEL - [7:0] */
+#define WM8915_MICD_LVL_SEL_SHIFT                    0  /* MICD_LVL_SEL - [7:0] */
+#define WM8915_MICD_LVL_SEL_WIDTH                    8  /* MICD_LVL_SEL - [7:0] */
+
+/*
+ * R58 (0x3A) - Mic Detect 3
+ */
+#define WM8915_MICD_LVL_MASK                    0x07FC  /* MICD_LVL - [10:2] */
+#define WM8915_MICD_LVL_SHIFT                        2  /* MICD_LVL - [10:2] */
+#define WM8915_MICD_LVL_WIDTH                        9  /* MICD_LVL - [10:2] */
+#define WM8915_MICD_VALID                       0x0002  /* MICD_VALID */
+#define WM8915_MICD_VALID_MASK                  0x0002  /* MICD_VALID */
+#define WM8915_MICD_VALID_SHIFT                      1  /* MICD_VALID */
+#define WM8915_MICD_VALID_WIDTH                      1  /* MICD_VALID */
+#define WM8915_MICD_STS                         0x0001  /* MICD_STS */
+#define WM8915_MICD_STS_MASK                    0x0001  /* MICD_STS */
+#define WM8915_MICD_STS_SHIFT                        0  /* MICD_STS */
+#define WM8915_MICD_STS_WIDTH                        1  /* MICD_STS */
+
+/*
+ * R64 (0x40) - Charge Pump (1)
+ */
+#define WM8915_CP_ENA                           0x8000  /* CP_ENA */
+#define WM8915_CP_ENA_MASK                      0x8000  /* CP_ENA */
+#define WM8915_CP_ENA_SHIFT                         15  /* CP_ENA */
+#define WM8915_CP_ENA_WIDTH                          1  /* CP_ENA */
+
+/*
+ * R65 (0x41) - Charge Pump (2)
+ */
+#define WM8915_CP_DISCH                         0x8000  /* CP_DISCH */
+#define WM8915_CP_DISCH_MASK                    0x8000  /* CP_DISCH */
+#define WM8915_CP_DISCH_SHIFT                       15  /* CP_DISCH */
+#define WM8915_CP_DISCH_WIDTH                        1  /* CP_DISCH */
+
+/*
+ * R80 (0x50) - DC Servo (1)
+ */
+#define WM8915_DCS_ENA_CHAN_3                   0x0008  /* DCS_ENA_CHAN_3 */
+#define WM8915_DCS_ENA_CHAN_3_MASK              0x0008  /* DCS_ENA_CHAN_3 */
+#define WM8915_DCS_ENA_CHAN_3_SHIFT                  3  /* DCS_ENA_CHAN_3 */
+#define WM8915_DCS_ENA_CHAN_3_WIDTH                  1  /* DCS_ENA_CHAN_3 */
+#define WM8915_DCS_ENA_CHAN_2                   0x0004  /* DCS_ENA_CHAN_2 */
+#define WM8915_DCS_ENA_CHAN_2_MASK              0x0004  /* DCS_ENA_CHAN_2 */
+#define WM8915_DCS_ENA_CHAN_2_SHIFT                  2  /* DCS_ENA_CHAN_2 */
+#define WM8915_DCS_ENA_CHAN_2_WIDTH                  1  /* DCS_ENA_CHAN_2 */
+#define WM8915_DCS_ENA_CHAN_1                   0x0002  /* DCS_ENA_CHAN_1 */
+#define WM8915_DCS_ENA_CHAN_1_MASK              0x0002  /* DCS_ENA_CHAN_1 */
+#define WM8915_DCS_ENA_CHAN_1_SHIFT                  1  /* DCS_ENA_CHAN_1 */
+#define WM8915_DCS_ENA_CHAN_1_WIDTH                  1  /* DCS_ENA_CHAN_1 */
+#define WM8915_DCS_ENA_CHAN_0                   0x0001  /* DCS_ENA_CHAN_0 */
+#define WM8915_DCS_ENA_CHAN_0_MASK              0x0001  /* DCS_ENA_CHAN_0 */
+#define WM8915_DCS_ENA_CHAN_0_SHIFT                  0  /* DCS_ENA_CHAN_0 */
+#define WM8915_DCS_ENA_CHAN_0_WIDTH                  1  /* DCS_ENA_CHAN_0 */
+
+/*
+ * R81 (0x51) - DC Servo (2)
+ */
+#define WM8915_DCS_TRIG_SINGLE_3                0x8000  /* DCS_TRIG_SINGLE_3 */
+#define WM8915_DCS_TRIG_SINGLE_3_MASK           0x8000  /* DCS_TRIG_SINGLE_3 */
+#define WM8915_DCS_TRIG_SINGLE_3_SHIFT              15  /* DCS_TRIG_SINGLE_3 */
+#define WM8915_DCS_TRIG_SINGLE_3_WIDTH               1  /* DCS_TRIG_SINGLE_3 */
+#define WM8915_DCS_TRIG_SINGLE_2                0x4000  /* DCS_TRIG_SINGLE_2 */
+#define WM8915_DCS_TRIG_SINGLE_2_MASK           0x4000  /* DCS_TRIG_SINGLE_2 */
+#define WM8915_DCS_TRIG_SINGLE_2_SHIFT              14  /* DCS_TRIG_SINGLE_2 */
+#define WM8915_DCS_TRIG_SINGLE_2_WIDTH               1  /* DCS_TRIG_SINGLE_2 */
+#define WM8915_DCS_TRIG_SINGLE_1                0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM8915_DCS_TRIG_SINGLE_1_MASK           0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM8915_DCS_TRIG_SINGLE_1_SHIFT              13  /* DCS_TRIG_SINGLE_1 */
+#define WM8915_DCS_TRIG_SINGLE_1_WIDTH               1  /* DCS_TRIG_SINGLE_1 */
+#define WM8915_DCS_TRIG_SINGLE_0                0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM8915_DCS_TRIG_SINGLE_0_MASK           0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM8915_DCS_TRIG_SINGLE_0_SHIFT              12  /* DCS_TRIG_SINGLE_0 */
+#define WM8915_DCS_TRIG_SINGLE_0_WIDTH               1  /* DCS_TRIG_SINGLE_0 */
+#define WM8915_DCS_TRIG_SERIES_3                0x0800  /* DCS_TRIG_SERIES_3 */
+#define WM8915_DCS_TRIG_SERIES_3_MASK           0x0800  /* DCS_TRIG_SERIES_3 */
+#define WM8915_DCS_TRIG_SERIES_3_SHIFT              11  /* DCS_TRIG_SERIES_3 */
+#define WM8915_DCS_TRIG_SERIES_3_WIDTH               1  /* DCS_TRIG_SERIES_3 */
+#define WM8915_DCS_TRIG_SERIES_2                0x0400  /* DCS_TRIG_SERIES_2 */
+#define WM8915_DCS_TRIG_SERIES_2_MASK           0x0400  /* DCS_TRIG_SERIES_2 */
+#define WM8915_DCS_TRIG_SERIES_2_SHIFT              10  /* DCS_TRIG_SERIES_2 */
+#define WM8915_DCS_TRIG_SERIES_2_WIDTH               1  /* DCS_TRIG_SERIES_2 */
+#define WM8915_DCS_TRIG_SERIES_1                0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM8915_DCS_TRIG_SERIES_1_MASK           0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM8915_DCS_TRIG_SERIES_1_SHIFT               9  /* DCS_TRIG_SERIES_1 */
+#define WM8915_DCS_TRIG_SERIES_1_WIDTH               1  /* DCS_TRIG_SERIES_1 */
+#define WM8915_DCS_TRIG_SERIES_0                0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM8915_DCS_TRIG_SERIES_0_MASK           0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM8915_DCS_TRIG_SERIES_0_SHIFT               8  /* DCS_TRIG_SERIES_0 */
+#define WM8915_DCS_TRIG_SERIES_0_WIDTH               1  /* DCS_TRIG_SERIES_0 */
+#define WM8915_DCS_TRIG_STARTUP_3               0x0080  /* DCS_TRIG_STARTUP_3 */
+#define WM8915_DCS_TRIG_STARTUP_3_MASK          0x0080  /* DCS_TRIG_STARTUP_3 */
+#define WM8915_DCS_TRIG_STARTUP_3_SHIFT              7  /* DCS_TRIG_STARTUP_3 */
+#define WM8915_DCS_TRIG_STARTUP_3_WIDTH              1  /* DCS_TRIG_STARTUP_3 */
+#define WM8915_DCS_TRIG_STARTUP_2               0x0040  /* DCS_TRIG_STARTUP_2 */
+#define WM8915_DCS_TRIG_STARTUP_2_MASK          0x0040  /* DCS_TRIG_STARTUP_2 */
+#define WM8915_DCS_TRIG_STARTUP_2_SHIFT              6  /* DCS_TRIG_STARTUP_2 */
+#define WM8915_DCS_TRIG_STARTUP_2_WIDTH              1  /* DCS_TRIG_STARTUP_2 */
+#define WM8915_DCS_TRIG_STARTUP_1               0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM8915_DCS_TRIG_STARTUP_1_MASK          0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM8915_DCS_TRIG_STARTUP_1_SHIFT              5  /* DCS_TRIG_STARTUP_1 */
+#define WM8915_DCS_TRIG_STARTUP_1_WIDTH              1  /* DCS_TRIG_STARTUP_1 */
+#define WM8915_DCS_TRIG_STARTUP_0               0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM8915_DCS_TRIG_STARTUP_0_MASK          0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM8915_DCS_TRIG_STARTUP_0_SHIFT              4  /* DCS_TRIG_STARTUP_0 */
+#define WM8915_DCS_TRIG_STARTUP_0_WIDTH              1  /* DCS_TRIG_STARTUP_0 */
+#define WM8915_DCS_TRIG_DAC_WR_3                0x0008  /* DCS_TRIG_DAC_WR_3 */
+#define WM8915_DCS_TRIG_DAC_WR_3_MASK           0x0008  /* DCS_TRIG_DAC_WR_3 */
+#define WM8915_DCS_TRIG_DAC_WR_3_SHIFT               3  /* DCS_TRIG_DAC_WR_3 */
+#define WM8915_DCS_TRIG_DAC_WR_3_WIDTH               1  /* DCS_TRIG_DAC_WR_3 */
+#define WM8915_DCS_TRIG_DAC_WR_2                0x0004  /* DCS_TRIG_DAC_WR_2 */
+#define WM8915_DCS_TRIG_DAC_WR_2_MASK           0x0004  /* DCS_TRIG_DAC_WR_2 */
+#define WM8915_DCS_TRIG_DAC_WR_2_SHIFT               2  /* DCS_TRIG_DAC_WR_2 */
+#define WM8915_DCS_TRIG_DAC_WR_2_WIDTH               1  /* DCS_TRIG_DAC_WR_2 */
+#define WM8915_DCS_TRIG_DAC_WR_1                0x0002  /* DCS_TRIG_DAC_WR_1 */
+#define WM8915_DCS_TRIG_DAC_WR_1_MASK           0x0002  /* DCS_TRIG_DAC_WR_1 */
+#define WM8915_DCS_TRIG_DAC_WR_1_SHIFT               1  /* DCS_TRIG_DAC_WR_1 */
+#define WM8915_DCS_TRIG_DAC_WR_1_WIDTH               1  /* DCS_TRIG_DAC_WR_1 */
+#define WM8915_DCS_TRIG_DAC_WR_0                0x0001  /* DCS_TRIG_DAC_WR_0 */
+#define WM8915_DCS_TRIG_DAC_WR_0_MASK           0x0001  /* DCS_TRIG_DAC_WR_0 */
+#define WM8915_DCS_TRIG_DAC_WR_0_SHIFT               0  /* DCS_TRIG_DAC_WR_0 */
+#define WM8915_DCS_TRIG_DAC_WR_0_WIDTH               1  /* DCS_TRIG_DAC_WR_0 */
+
+/*
+ * R82 (0x52) - DC Servo (3)
+ */
+#define WM8915_DCS_TIMER_PERIOD_23_MASK         0x0F00  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8915_DCS_TIMER_PERIOD_23_SHIFT             8  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8915_DCS_TIMER_PERIOD_23_WIDTH             4  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8915_DCS_TIMER_PERIOD_01_MASK         0x000F  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8915_DCS_TIMER_PERIOD_01_SHIFT             0  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8915_DCS_TIMER_PERIOD_01_WIDTH             4  /* DCS_TIMER_PERIOD_01 - [3:0] */
+
+/*
+ * R84 (0x54) - DC Servo (5)
+ */
+#define WM8915_DCS_SERIES_NO_23_MASK            0x7F00  /* DCS_SERIES_NO_23 - [14:8] */
+#define WM8915_DCS_SERIES_NO_23_SHIFT                8  /* DCS_SERIES_NO_23 - [14:8] */
+#define WM8915_DCS_SERIES_NO_23_WIDTH                7  /* DCS_SERIES_NO_23 - [14:8] */
+#define WM8915_DCS_SERIES_NO_01_MASK            0x007F  /* DCS_SERIES_NO_01 - [6:0] */
+#define WM8915_DCS_SERIES_NO_01_SHIFT                0  /* DCS_SERIES_NO_01 - [6:0] */
+#define WM8915_DCS_SERIES_NO_01_WIDTH                7  /* DCS_SERIES_NO_01 - [6:0] */
+
+/*
+ * R85 (0x55) - DC Servo (6)
+ */
+#define WM8915_DCS_DAC_WR_VAL_3_MASK            0xFF00  /* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8915_DCS_DAC_WR_VAL_3_SHIFT                8  /* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8915_DCS_DAC_WR_VAL_3_WIDTH                8  /* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8915_DCS_DAC_WR_VAL_2_MASK            0x00FF  /* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8915_DCS_DAC_WR_VAL_2_SHIFT                0  /* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8915_DCS_DAC_WR_VAL_2_WIDTH                8  /* DCS_DAC_WR_VAL_2 - [7:0] */
+
+/*
+ * R86 (0x56) - DC Servo (7)
+ */
+#define WM8915_DCS_DAC_WR_VAL_1_MASK            0xFF00  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8915_DCS_DAC_WR_VAL_1_SHIFT                8  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8915_DCS_DAC_WR_VAL_1_WIDTH                8  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8915_DCS_DAC_WR_VAL_0_MASK            0x00FF  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8915_DCS_DAC_WR_VAL_0_SHIFT                0  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8915_DCS_DAC_WR_VAL_0_WIDTH                8  /* DCS_DAC_WR_VAL_0 - [7:0] */
+
+/*
+ * R87 (0x57) - DC Servo Readback 0
+ */
+#define WM8915_DCS_CAL_COMPLETE_MASK            0x0F00  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8915_DCS_CAL_COMPLETE_SHIFT                8  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8915_DCS_CAL_COMPLETE_WIDTH                4  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8915_DCS_DAC_WR_COMPLETE_MASK         0x00F0  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8915_DCS_DAC_WR_COMPLETE_SHIFT             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8915_DCS_DAC_WR_COMPLETE_WIDTH             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8915_DCS_STARTUP_COMPLETE_MASK        0x000F  /* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8915_DCS_STARTUP_COMPLETE_SHIFT            0  /* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8915_DCS_STARTUP_COMPLETE_WIDTH            4  /* DCS_STARTUP_COMPLETE - [3:0] */
+
+/*
+ * R96 (0x60) - Analogue HP (1)
+ */
+#define WM8915_HPOUT1L_RMV_SHORT                0x0080  /* HPOUT1L_RMV_SHORT */
+#define WM8915_HPOUT1L_RMV_SHORT_MASK           0x0080  /* HPOUT1L_RMV_SHORT */
+#define WM8915_HPOUT1L_RMV_SHORT_SHIFT               7  /* HPOUT1L_RMV_SHORT */
+#define WM8915_HPOUT1L_RMV_SHORT_WIDTH               1  /* HPOUT1L_RMV_SHORT */
+#define WM8915_HPOUT1L_OUTP                     0x0040  /* HPOUT1L_OUTP */
+#define WM8915_HPOUT1L_OUTP_MASK                0x0040  /* HPOUT1L_OUTP */
+#define WM8915_HPOUT1L_OUTP_SHIFT                    6  /* HPOUT1L_OUTP */
+#define WM8915_HPOUT1L_OUTP_WIDTH                    1  /* HPOUT1L_OUTP */
+#define WM8915_HPOUT1L_DLY                      0x0020  /* HPOUT1L_DLY */
+#define WM8915_HPOUT1L_DLY_MASK                 0x0020  /* HPOUT1L_DLY */
+#define WM8915_HPOUT1L_DLY_SHIFT                     5  /* HPOUT1L_DLY */
+#define WM8915_HPOUT1L_DLY_WIDTH                     1  /* HPOUT1L_DLY */
+#define WM8915_HPOUT1R_RMV_SHORT                0x0008  /* HPOUT1R_RMV_SHORT */
+#define WM8915_HPOUT1R_RMV_SHORT_MASK           0x0008  /* HPOUT1R_RMV_SHORT */
+#define WM8915_HPOUT1R_RMV_SHORT_SHIFT               3  /* HPOUT1R_RMV_SHORT */
+#define WM8915_HPOUT1R_RMV_SHORT_WIDTH               1  /* HPOUT1R_RMV_SHORT */
+#define WM8915_HPOUT1R_OUTP                     0x0004  /* HPOUT1R_OUTP */
+#define WM8915_HPOUT1R_OUTP_MASK                0x0004  /* HPOUT1R_OUTP */
+#define WM8915_HPOUT1R_OUTP_SHIFT                    2  /* HPOUT1R_OUTP */
+#define WM8915_HPOUT1R_OUTP_WIDTH                    1  /* HPOUT1R_OUTP */
+#define WM8915_HPOUT1R_DLY                      0x0002  /* HPOUT1R_DLY */
+#define WM8915_HPOUT1R_DLY_MASK                 0x0002  /* HPOUT1R_DLY */
+#define WM8915_HPOUT1R_DLY_SHIFT                     1  /* HPOUT1R_DLY */
+#define WM8915_HPOUT1R_DLY_WIDTH                     1  /* HPOUT1R_DLY */
+
+/*
+ * R97 (0x61) - Analogue HP (2)
+ */
+#define WM8915_HPOUT2L_RMV_SHORT                0x0080  /* HPOUT2L_RMV_SHORT */
+#define WM8915_HPOUT2L_RMV_SHORT_MASK           0x0080  /* HPOUT2L_RMV_SHORT */
+#define WM8915_HPOUT2L_RMV_SHORT_SHIFT               7  /* HPOUT2L_RMV_SHORT */
+#define WM8915_HPOUT2L_RMV_SHORT_WIDTH               1  /* HPOUT2L_RMV_SHORT */
+#define WM8915_HPOUT2L_OUTP                     0x0040  /* HPOUT2L_OUTP */
+#define WM8915_HPOUT2L_OUTP_MASK                0x0040  /* HPOUT2L_OUTP */
+#define WM8915_HPOUT2L_OUTP_SHIFT                    6  /* HPOUT2L_OUTP */
+#define WM8915_HPOUT2L_OUTP_WIDTH                    1  /* HPOUT2L_OUTP */
+#define WM8915_HPOUT2L_DLY                      0x0020  /* HPOUT2L_DLY */
+#define WM8915_HPOUT2L_DLY_MASK                 0x0020  /* HPOUT2L_DLY */
+#define WM8915_HPOUT2L_DLY_SHIFT                     5  /* HPOUT2L_DLY */
+#define WM8915_HPOUT2L_DLY_WIDTH                     1  /* HPOUT2L_DLY */
+#define WM8915_HPOUT2R_RMV_SHORT                0x0008  /* HPOUT2R_RMV_SHORT */
+#define WM8915_HPOUT2R_RMV_SHORT_MASK           0x0008  /* HPOUT2R_RMV_SHORT */
+#define WM8915_HPOUT2R_RMV_SHORT_SHIFT               3  /* HPOUT2R_RMV_SHORT */
+#define WM8915_HPOUT2R_RMV_SHORT_WIDTH               1  /* HPOUT2R_RMV_SHORT */
+#define WM8915_HPOUT2R_OUTP                     0x0004  /* HPOUT2R_OUTP */
+#define WM8915_HPOUT2R_OUTP_MASK                0x0004  /* HPOUT2R_OUTP */
+#define WM8915_HPOUT2R_OUTP_SHIFT                    2  /* HPOUT2R_OUTP */
+#define WM8915_HPOUT2R_OUTP_WIDTH                    1  /* HPOUT2R_OUTP */
+#define WM8915_HPOUT2R_DLY                      0x0002  /* HPOUT2R_DLY */
+#define WM8915_HPOUT2R_DLY_MASK                 0x0002  /* HPOUT2R_DLY */
+#define WM8915_HPOUT2R_DLY_SHIFT                     1  /* HPOUT2R_DLY */
+#define WM8915_HPOUT2R_DLY_WIDTH                     1  /* HPOUT2R_DLY */
+
+/*
+ * R256 (0x100) - Chip Revision
+ */
+#define WM8915_CHIP_REV_MASK                    0x000F  /* CHIP_REV - [3:0] */
+#define WM8915_CHIP_REV_SHIFT                        0  /* CHIP_REV - [3:0] */
+#define WM8915_CHIP_REV_WIDTH                        4  /* CHIP_REV - [3:0] */
+
+/*
+ * R257 (0x101) - Control Interface (1)
+ */
+#define WM8915_AUTO_INC                         0x0004  /* AUTO_INC */
+#define WM8915_AUTO_INC_MASK                    0x0004  /* AUTO_INC */
+#define WM8915_AUTO_INC_SHIFT                        2  /* AUTO_INC */
+#define WM8915_AUTO_INC_WIDTH                        1  /* AUTO_INC */
+
+/*
+ * R272 (0x110) - Write Sequencer Ctrl (1)
+ */
+#define WM8915_WSEQ_ENA                         0x8000  /* WSEQ_ENA */
+#define WM8915_WSEQ_ENA_MASK                    0x8000  /* WSEQ_ENA */
+#define WM8915_WSEQ_ENA_SHIFT                       15  /* WSEQ_ENA */
+#define WM8915_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+#define WM8915_WSEQ_ABORT                       0x0200  /* WSEQ_ABORT */
+#define WM8915_WSEQ_ABORT_MASK                  0x0200  /* WSEQ_ABORT */
+#define WM8915_WSEQ_ABORT_SHIFT                      9  /* WSEQ_ABORT */
+#define WM8915_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define WM8915_WSEQ_START                       0x0100  /* WSEQ_START */
+#define WM8915_WSEQ_START_MASK                  0x0100  /* WSEQ_START */
+#define WM8915_WSEQ_START_SHIFT                      8  /* WSEQ_START */
+#define WM8915_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define WM8915_WSEQ_START_INDEX_MASK            0x007F  /* WSEQ_START_INDEX - [6:0] */
+#define WM8915_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [6:0] */
+#define WM8915_WSEQ_START_INDEX_WIDTH                7  /* WSEQ_START_INDEX - [6:0] */
+
+/*
+ * R273 (0x111) - Write Sequencer Ctrl (2)
+ */
+#define WM8915_WSEQ_BUSY                        0x0100  /* WSEQ_BUSY */
+#define WM8915_WSEQ_BUSY_MASK                   0x0100  /* WSEQ_BUSY */
+#define WM8915_WSEQ_BUSY_SHIFT                       8  /* WSEQ_BUSY */
+#define WM8915_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+#define WM8915_WSEQ_CURRENT_INDEX_MASK          0x007F  /* WSEQ_CURRENT_INDEX - [6:0] */
+#define WM8915_WSEQ_CURRENT_INDEX_SHIFT              0  /* WSEQ_CURRENT_INDEX - [6:0] */
+#define WM8915_WSEQ_CURRENT_INDEX_WIDTH              7  /* WSEQ_CURRENT_INDEX - [6:0] */
+
+/*
+ * R512 (0x200) - AIF Clocking (1)
+ */
+#define WM8915_SYSCLK_SRC_MASK                  0x0018  /* SYSCLK_SRC - [4:3] */
+#define WM8915_SYSCLK_SRC_SHIFT                      3  /* SYSCLK_SRC - [4:3] */
+#define WM8915_SYSCLK_SRC_WIDTH                      2  /* SYSCLK_SRC - [4:3] */
+#define WM8915_SYSCLK_INV                       0x0004  /* SYSCLK_INV */
+#define WM8915_SYSCLK_INV_MASK                  0x0004  /* SYSCLK_INV */
+#define WM8915_SYSCLK_INV_SHIFT                      2  /* SYSCLK_INV */
+#define WM8915_SYSCLK_INV_WIDTH                      1  /* SYSCLK_INV */
+#define WM8915_SYSCLK_DIV                       0x0002  /* SYSCLK_DIV */
+#define WM8915_SYSCLK_DIV_MASK                  0x0002  /* SYSCLK_DIV */
+#define WM8915_SYSCLK_DIV_SHIFT                      1  /* SYSCLK_DIV */
+#define WM8915_SYSCLK_DIV_WIDTH                      1  /* SYSCLK_DIV */
+#define WM8915_SYSCLK_ENA                       0x0001  /* SYSCLK_ENA */
+#define WM8915_SYSCLK_ENA_MASK                  0x0001  /* SYSCLK_ENA */
+#define WM8915_SYSCLK_ENA_SHIFT                      0  /* SYSCLK_ENA */
+#define WM8915_SYSCLK_ENA_WIDTH                      1  /* SYSCLK_ENA */
+
+/*
+ * R513 (0x201) - AIF Clocking (2)
+ */
+#define WM8915_DSP2_DIV_MASK                    0x0018  /* DSP2_DIV - [4:3] */
+#define WM8915_DSP2_DIV_SHIFT                        3  /* DSP2_DIV - [4:3] */
+#define WM8915_DSP2_DIV_WIDTH                        2  /* DSP2_DIV - [4:3] */
+#define WM8915_DSP1_DIV_MASK                    0x0003  /* DSP1_DIV - [1:0] */
+#define WM8915_DSP1_DIV_SHIFT                        0  /* DSP1_DIV - [1:0] */
+#define WM8915_DSP1_DIV_WIDTH                        2  /* DSP1_DIV - [1:0] */
+
+/*
+ * R520 (0x208) - Clocking (1)
+ */
+#define WM8915_LFCLK_ENA                        0x0020  /* LFCLK_ENA */
+#define WM8915_LFCLK_ENA_MASK                   0x0020  /* LFCLK_ENA */
+#define WM8915_LFCLK_ENA_SHIFT                       5  /* LFCLK_ENA */
+#define WM8915_LFCLK_ENA_WIDTH                       1  /* LFCLK_ENA */
+#define WM8915_TOCLK_ENA                        0x0010  /* TOCLK_ENA */
+#define WM8915_TOCLK_ENA_MASK                   0x0010  /* TOCLK_ENA */
+#define WM8915_TOCLK_ENA_SHIFT                       4  /* TOCLK_ENA */
+#define WM8915_TOCLK_ENA_WIDTH                       1  /* TOCLK_ENA */
+#define WM8915_AIFCLK_ENA                       0x0004  /* AIFCLK_ENA */
+#define WM8915_AIFCLK_ENA_MASK                  0x0004  /* AIFCLK_ENA */
+#define WM8915_AIFCLK_ENA_SHIFT                      2  /* AIFCLK_ENA */
+#define WM8915_AIFCLK_ENA_WIDTH                      1  /* AIFCLK_ENA */
+#define WM8915_SYSDSPCLK_ENA                    0x0002  /* SYSDSPCLK_ENA */
+#define WM8915_SYSDSPCLK_ENA_MASK               0x0002  /* SYSDSPCLK_ENA */
+#define WM8915_SYSDSPCLK_ENA_SHIFT                   1  /* SYSDSPCLK_ENA */
+#define WM8915_SYSDSPCLK_ENA_WIDTH                   1  /* SYSDSPCLK_ENA */
+
+/*
+ * R521 (0x209) - Clocking (2)
+ */
+#define WM8915_TOCLK_DIV_MASK                   0x0700  /* TOCLK_DIV - [10:8] */
+#define WM8915_TOCLK_DIV_SHIFT                       8  /* TOCLK_DIV - [10:8] */
+#define WM8915_TOCLK_DIV_WIDTH                       3  /* TOCLK_DIV - [10:8] */
+#define WM8915_DBCLK_DIV_MASK                   0x00F0  /* DBCLK_DIV - [7:4] */
+#define WM8915_DBCLK_DIV_SHIFT                       4  /* DBCLK_DIV - [7:4] */
+#define WM8915_DBCLK_DIV_WIDTH                       4  /* DBCLK_DIV - [7:4] */
+#define WM8915_OPCLK_DIV_MASK                   0x0007  /* OPCLK_DIV - [2:0] */
+#define WM8915_OPCLK_DIV_SHIFT                       0  /* OPCLK_DIV - [2:0] */
+#define WM8915_OPCLK_DIV_WIDTH                       3  /* OPCLK_DIV - [2:0] */
+
+/*
+ * R528 (0x210) - AIF Rate
+ */
+#define WM8915_SYSCLK_RATE                      0x0001  /* SYSCLK_RATE */
+#define WM8915_SYSCLK_RATE_MASK                 0x0001  /* SYSCLK_RATE */
+#define WM8915_SYSCLK_RATE_SHIFT                     0  /* SYSCLK_RATE */
+#define WM8915_SYSCLK_RATE_WIDTH                     1  /* SYSCLK_RATE */
+
+/*
+ * R544 (0x220) - FLL Control (1)
+ */
+#define WM8915_FLL_OSC_ENA                      0x0002  /* FLL_OSC_ENA */
+#define WM8915_FLL_OSC_ENA_MASK                 0x0002  /* FLL_OSC_ENA */
+#define WM8915_FLL_OSC_ENA_SHIFT                     1  /* FLL_OSC_ENA */
+#define WM8915_FLL_OSC_ENA_WIDTH                     1  /* FLL_OSC_ENA */
+#define WM8915_FLL_ENA                          0x0001  /* FLL_ENA */
+#define WM8915_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
+#define WM8915_FLL_ENA_SHIFT                         0  /* FLL_ENA */
+#define WM8915_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+
+/*
+ * R545 (0x221) - FLL Control (2)
+ */
+#define WM8915_FLL_OUTDIV_MASK                  0x3F00  /* FLL_OUTDIV - [13:8] */
+#define WM8915_FLL_OUTDIV_SHIFT                      8  /* FLL_OUTDIV - [13:8] */
+#define WM8915_FLL_OUTDIV_WIDTH                      6  /* FLL_OUTDIV - [13:8] */
+#define WM8915_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
+#define WM8915_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
+#define WM8915_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
+
+/*
+ * R546 (0x222) - FLL Control (3)
+ */
+#define WM8915_FLL_THETA_MASK                   0xFFFF  /* FLL_THETA - [15:0] */
+#define WM8915_FLL_THETA_SHIFT                       0  /* FLL_THETA - [15:0] */
+#define WM8915_FLL_THETA_WIDTH                      16  /* FLL_THETA - [15:0] */
+
+/*
+ * R547 (0x223) - FLL Control (4)
+ */
+#define WM8915_FLL_N_MASK                       0x7FE0  /* FLL_N - [14:5] */
+#define WM8915_FLL_N_SHIFT                           5  /* FLL_N - [14:5] */
+#define WM8915_FLL_N_WIDTH                          10  /* FLL_N - [14:5] */
+#define WM8915_FLL_LOOP_GAIN_MASK               0x000F  /* FLL_LOOP_GAIN - [3:0] */
+#define WM8915_FLL_LOOP_GAIN_SHIFT                   0  /* FLL_LOOP_GAIN - [3:0] */
+#define WM8915_FLL_LOOP_GAIN_WIDTH                   4  /* FLL_LOOP_GAIN - [3:0] */
+
+/*
+ * R548 (0x224) - FLL Control (5)
+ */
+#define WM8915_FLL_FRC_NCO_VAL_MASK             0x1F80  /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8915_FLL_FRC_NCO_VAL_SHIFT                 7  /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8915_FLL_FRC_NCO_VAL_WIDTH                 6  /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8915_FLL_FRC_NCO                      0x0040  /* FLL_FRC_NCO */
+#define WM8915_FLL_FRC_NCO_MASK                 0x0040  /* FLL_FRC_NCO */
+#define WM8915_FLL_FRC_NCO_SHIFT                     6  /* FLL_FRC_NCO */
+#define WM8915_FLL_FRC_NCO_WIDTH                     1  /* FLL_FRC_NCO */
+#define WM8915_FLL_REFCLK_DIV_MASK              0x0018  /* FLL_REFCLK_DIV - [4:3] */
+#define WM8915_FLL_REFCLK_DIV_SHIFT                  3  /* FLL_REFCLK_DIV - [4:3] */
+#define WM8915_FLL_REFCLK_DIV_WIDTH                  2  /* FLL_REFCLK_DIV - [4:3] */
+#define WM8915_FLL_REF_FREQ                     0x0004  /* FLL_REF_FREQ */
+#define WM8915_FLL_REF_FREQ_MASK                0x0004  /* FLL_REF_FREQ */
+#define WM8915_FLL_REF_FREQ_SHIFT                    2  /* FLL_REF_FREQ */
+#define WM8915_FLL_REF_FREQ_WIDTH                    1  /* FLL_REF_FREQ */
+#define WM8915_FLL_REFCLK_SRC_MASK              0x0003  /* FLL_REFCLK_SRC - [1:0] */
+#define WM8915_FLL_REFCLK_SRC_SHIFT                  0  /* FLL_REFCLK_SRC - [1:0] */
+#define WM8915_FLL_REFCLK_SRC_WIDTH                  2  /* FLL_REFCLK_SRC - [1:0] */
+
+/*
+ * R549 (0x225) - FLL Control (6)
+ */
+#define WM8915_FLL_REFCLK_SRC_STS_MASK          0x000C  /* FLL_REFCLK_SRC_STS - [3:2] */
+#define WM8915_FLL_REFCLK_SRC_STS_SHIFT              2  /* FLL_REFCLK_SRC_STS - [3:2] */
+#define WM8915_FLL_REFCLK_SRC_STS_WIDTH              2  /* FLL_REFCLK_SRC_STS - [3:2] */
+#define WM8915_FLL_SWITCH_CLK                   0x0001  /* FLL_SWITCH_CLK */
+#define WM8915_FLL_SWITCH_CLK_MASK              0x0001  /* FLL_SWITCH_CLK */
+#define WM8915_FLL_SWITCH_CLK_SHIFT                  0  /* FLL_SWITCH_CLK */
+#define WM8915_FLL_SWITCH_CLK_WIDTH                  1  /* FLL_SWITCH_CLK */
+
+/*
+ * R550 (0x226) - FLL EFS 1
+ */
+#define WM8915_FLL_LAMBDA_MASK                  0xFFFF  /* FLL_LAMBDA - [15:0] */
+#define WM8915_FLL_LAMBDA_SHIFT                      0  /* FLL_LAMBDA - [15:0] */
+#define WM8915_FLL_LAMBDA_WIDTH                     16  /* FLL_LAMBDA - [15:0] */
+
+/*
+ * R551 (0x227) - FLL EFS 2
+ */
+#define WM8915_FLL_LFSR_SEL_MASK                0x0006  /* FLL_LFSR_SEL - [2:1] */
+#define WM8915_FLL_LFSR_SEL_SHIFT                    1  /* FLL_LFSR_SEL - [2:1] */
+#define WM8915_FLL_LFSR_SEL_WIDTH                    2  /* FLL_LFSR_SEL - [2:1] */
+#define WM8915_FLL_EFS_ENA                      0x0001  /* FLL_EFS_ENA */
+#define WM8915_FLL_EFS_ENA_MASK                 0x0001  /* FLL_EFS_ENA */
+#define WM8915_FLL_EFS_ENA_SHIFT                     0  /* FLL_EFS_ENA */
+#define WM8915_FLL_EFS_ENA_WIDTH                     1  /* FLL_EFS_ENA */
+
+/*
+ * R768 (0x300) - AIF1 Control
+ */
+#define WM8915_AIF1_TRI                         0x0004  /* AIF1_TRI */
+#define WM8915_AIF1_TRI_MASK                    0x0004  /* AIF1_TRI */
+#define WM8915_AIF1_TRI_SHIFT                        2  /* AIF1_TRI */
+#define WM8915_AIF1_TRI_WIDTH                        1  /* AIF1_TRI */
+#define WM8915_AIF1_FMT_MASK                    0x0003  /* AIF1_FMT - [1:0] */
+#define WM8915_AIF1_FMT_SHIFT                        0  /* AIF1_FMT - [1:0] */
+#define WM8915_AIF1_FMT_WIDTH                        2  /* AIF1_FMT - [1:0] */
+
+/*
+ * R769 (0x301) - AIF1 BCLK
+ */
+#define WM8915_AIF1_BCLK_INV                    0x0400  /* AIF1_BCLK_INV */
+#define WM8915_AIF1_BCLK_INV_MASK               0x0400  /* AIF1_BCLK_INV */
+#define WM8915_AIF1_BCLK_INV_SHIFT                  10  /* AIF1_BCLK_INV */
+#define WM8915_AIF1_BCLK_INV_WIDTH                   1  /* AIF1_BCLK_INV */
+#define WM8915_AIF1_BCLK_FRC                    0x0200  /* AIF1_BCLK_FRC */
+#define WM8915_AIF1_BCLK_FRC_MASK               0x0200  /* AIF1_BCLK_FRC */
+#define WM8915_AIF1_BCLK_FRC_SHIFT                   9  /* AIF1_BCLK_FRC */
+#define WM8915_AIF1_BCLK_FRC_WIDTH                   1  /* AIF1_BCLK_FRC */
+#define WM8915_AIF1_BCLK_MSTR                   0x0100  /* AIF1_BCLK_MSTR */
+#define WM8915_AIF1_BCLK_MSTR_MASK              0x0100  /* AIF1_BCLK_MSTR */
+#define WM8915_AIF1_BCLK_MSTR_SHIFT                  8  /* AIF1_BCLK_MSTR */
+#define WM8915_AIF1_BCLK_MSTR_WIDTH                  1  /* AIF1_BCLK_MSTR */
+#define WM8915_AIF1_BCLK_DIV_MASK               0x000F  /* AIF1_BCLK_DIV - [3:0] */
+#define WM8915_AIF1_BCLK_DIV_SHIFT                   0  /* AIF1_BCLK_DIV - [3:0] */
+#define WM8915_AIF1_BCLK_DIV_WIDTH                   4  /* AIF1_BCLK_DIV - [3:0] */
+
+/*
+ * R770 (0x302) - AIF1 TX LRCLK(1)
+ */
+#define WM8915_AIF1TX_RATE_MASK                 0x07FF  /* AIF1TX_RATE - [10:0] */
+#define WM8915_AIF1TX_RATE_SHIFT                     0  /* AIF1TX_RATE - [10:0] */
+#define WM8915_AIF1TX_RATE_WIDTH                    11  /* AIF1TX_RATE - [10:0] */
+
+/*
+ * R771 (0x303) - AIF1 TX LRCLK(2)
+ */
+#define WM8915_AIF1TX_LRCLK_MODE                0x0008  /* AIF1TX_LRCLK_MODE */
+#define WM8915_AIF1TX_LRCLK_MODE_MASK           0x0008  /* AIF1TX_LRCLK_MODE */
+#define WM8915_AIF1TX_LRCLK_MODE_SHIFT               3  /* AIF1TX_LRCLK_MODE */
+#define WM8915_AIF1TX_LRCLK_MODE_WIDTH               1  /* AIF1TX_LRCLK_MODE */
+#define WM8915_AIF1TX_LRCLK_INV                 0x0004  /* AIF1TX_LRCLK_INV */
+#define WM8915_AIF1TX_LRCLK_INV_MASK            0x0004  /* AIF1TX_LRCLK_INV */
+#define WM8915_AIF1TX_LRCLK_INV_SHIFT                2  /* AIF1TX_LRCLK_INV */
+#define WM8915_AIF1TX_LRCLK_INV_WIDTH                1  /* AIF1TX_LRCLK_INV */
+#define WM8915_AIF1TX_LRCLK_FRC                 0x0002  /* AIF1TX_LRCLK_FRC */
+#define WM8915_AIF1TX_LRCLK_FRC_MASK            0x0002  /* AIF1TX_LRCLK_FRC */
+#define WM8915_AIF1TX_LRCLK_FRC_SHIFT                1  /* AIF1TX_LRCLK_FRC */
+#define WM8915_AIF1TX_LRCLK_FRC_WIDTH                1  /* AIF1TX_LRCLK_FRC */
+#define WM8915_AIF1TX_LRCLK_MSTR                0x0001  /* AIF1TX_LRCLK_MSTR */
+#define WM8915_AIF1TX_LRCLK_MSTR_MASK           0x0001  /* AIF1TX_LRCLK_MSTR */
+#define WM8915_AIF1TX_LRCLK_MSTR_SHIFT               0  /* AIF1TX_LRCLK_MSTR */
+#define WM8915_AIF1TX_LRCLK_MSTR_WIDTH               1  /* AIF1TX_LRCLK_MSTR */
+
+/*
+ * R772 (0x304) - AIF1 RX LRCLK(1)
+ */
+#define WM8915_AIF1RX_RATE_MASK                 0x07FF  /* AIF1RX_RATE - [10:0] */
+#define WM8915_AIF1RX_RATE_SHIFT                     0  /* AIF1RX_RATE - [10:0] */
+#define WM8915_AIF1RX_RATE_WIDTH                    11  /* AIF1RX_RATE - [10:0] */
+
+/*
+ * R773 (0x305) - AIF1 RX LRCLK(2)
+ */
+#define WM8915_AIF1RX_LRCLK_INV                 0x0004  /* AIF1RX_LRCLK_INV */
+#define WM8915_AIF1RX_LRCLK_INV_MASK            0x0004  /* AIF1RX_LRCLK_INV */
+#define WM8915_AIF1RX_LRCLK_INV_SHIFT                2  /* AIF1RX_LRCLK_INV */
+#define WM8915_AIF1RX_LRCLK_INV_WIDTH                1  /* AIF1RX_LRCLK_INV */
+#define WM8915_AIF1RX_LRCLK_FRC                 0x0002  /* AIF1RX_LRCLK_FRC */
+#define WM8915_AIF1RX_LRCLK_FRC_MASK            0x0002  /* AIF1RX_LRCLK_FRC */
+#define WM8915_AIF1RX_LRCLK_FRC_SHIFT                1  /* AIF1RX_LRCLK_FRC */
+#define WM8915_AIF1RX_LRCLK_FRC_WIDTH                1  /* AIF1RX_LRCLK_FRC */
+#define WM8915_AIF1RX_LRCLK_MSTR                0x0001  /* AIF1RX_LRCLK_MSTR */
+#define WM8915_AIF1RX_LRCLK_MSTR_MASK           0x0001  /* AIF1RX_LRCLK_MSTR */
+#define WM8915_AIF1RX_LRCLK_MSTR_SHIFT               0  /* AIF1RX_LRCLK_MSTR */
+#define WM8915_AIF1RX_LRCLK_MSTR_WIDTH               1  /* AIF1RX_LRCLK_MSTR */
+
+/*
+ * R774 (0x306) - AIF1TX Data Configuration (1)
+ */
+#define WM8915_AIF1TX_WL_MASK                   0xFF00  /* AIF1TX_WL - [15:8] */
+#define WM8915_AIF1TX_WL_SHIFT                       8  /* AIF1TX_WL - [15:8] */
+#define WM8915_AIF1TX_WL_WIDTH                       8  /* AIF1TX_WL - [15:8] */
+#define WM8915_AIF1TX_SLOT_LEN_MASK             0x00FF  /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM8915_AIF1TX_SLOT_LEN_SHIFT                 0  /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM8915_AIF1TX_SLOT_LEN_WIDTH                 8  /* AIF1TX_SLOT_LEN - [7:0] */
+
+/*
+ * R775 (0x307) - AIF1TX Data Configuration (2)
+ */
+#define WM8915_AIF1TX_DAT_TRI                   0x0001  /* AIF1TX_DAT_TRI */
+#define WM8915_AIF1TX_DAT_TRI_MASK              0x0001  /* AIF1TX_DAT_TRI */
+#define WM8915_AIF1TX_DAT_TRI_SHIFT                  0  /* AIF1TX_DAT_TRI */
+#define WM8915_AIF1TX_DAT_TRI_WIDTH                  1  /* AIF1TX_DAT_TRI */
+
+/*
+ * R776 (0x308) - AIF1RX Data Configuration
+ */
+#define WM8915_AIF1RX_WL_MASK                   0xFF00  /* AIF1RX_WL - [15:8] */
+#define WM8915_AIF1RX_WL_SHIFT                       8  /* AIF1RX_WL - [15:8] */
+#define WM8915_AIF1RX_WL_WIDTH                       8  /* AIF1RX_WL - [15:8] */
+#define WM8915_AIF1RX_SLOT_LEN_MASK             0x00FF  /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM8915_AIF1RX_SLOT_LEN_SHIFT                 0  /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM8915_AIF1RX_SLOT_LEN_WIDTH                 8  /* AIF1RX_SLOT_LEN - [7:0] */
+
+/*
+ * R777 (0x309) - AIF1TX Channel 0 Configuration
+ */
+#define WM8915_AIF1TX_CHAN0_DAT_INV             0x8000  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8915_AIF1TX_CHAN0_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8915_AIF1TX_CHAN0_DAT_INV_SHIFT           15  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8915_AIF1TX_CHAN0_DAT_INV_WIDTH            1  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8915_AIF1TX_CHAN0_SPACING_MASK        0x7E00  /* AIF1TX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN0_SPACING_SHIFT            9  /* AIF1TX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN0_SPACING_WIDTH            6  /* AIF1TX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN0_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN0_SLOTS_SHIFT              6  /* AIF1TX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN0_SLOTS_WIDTH              3  /* AIF1TX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN0_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN0_START_SLOT_SHIFT         0  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN0_START_SLOT_WIDTH         6  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R778 (0x30A) - AIF1TX Channel 1 Configuration
+ */
+#define WM8915_AIF1TX_CHAN1_DAT_INV             0x8000  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8915_AIF1TX_CHAN1_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8915_AIF1TX_CHAN1_DAT_INV_SHIFT           15  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8915_AIF1TX_CHAN1_DAT_INV_WIDTH            1  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8915_AIF1TX_CHAN1_SPACING_MASK        0x7E00  /* AIF1TX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN1_SPACING_SHIFT            9  /* AIF1TX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN1_SPACING_WIDTH            6  /* AIF1TX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN1_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN1_SLOTS_SHIFT              6  /* AIF1TX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN1_SLOTS_WIDTH              3  /* AIF1TX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN1_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN1_START_SLOT_SHIFT         0  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN1_START_SLOT_WIDTH         6  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R779 (0x30B) - AIF1TX Channel 2 Configuration
+ */
+#define WM8915_AIF1TX_CHAN2_DAT_INV             0x8000  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8915_AIF1TX_CHAN2_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8915_AIF1TX_CHAN2_DAT_INV_SHIFT           15  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8915_AIF1TX_CHAN2_DAT_INV_WIDTH            1  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8915_AIF1TX_CHAN2_SPACING_MASK        0x7E00  /* AIF1TX_CHAN2_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN2_SPACING_SHIFT            9  /* AIF1TX_CHAN2_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN2_SPACING_WIDTH            6  /* AIF1TX_CHAN2_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN2_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN2_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN2_SLOTS_SHIFT              6  /* AIF1TX_CHAN2_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN2_SLOTS_WIDTH              3  /* AIF1TX_CHAN2_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN2_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN2_START_SLOT_SHIFT         0  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN2_START_SLOT_WIDTH         6  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
+
+/*
+ * R780 (0x30C) - AIF1TX Channel 3 Configuration
+ */
+#define WM8915_AIF1TX_CHAN3_DAT_INV             0x8000  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8915_AIF1TX_CHAN3_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8915_AIF1TX_CHAN3_DAT_INV_SHIFT           15  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8915_AIF1TX_CHAN3_DAT_INV_WIDTH            1  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8915_AIF1TX_CHAN3_SPACING_MASK        0x7E00  /* AIF1TX_CHAN3_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN3_SPACING_SHIFT            9  /* AIF1TX_CHAN3_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN3_SPACING_WIDTH            6  /* AIF1TX_CHAN3_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN3_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN3_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN3_SLOTS_SHIFT              6  /* AIF1TX_CHAN3_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN3_SLOTS_WIDTH              3  /* AIF1TX_CHAN3_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN3_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN3_START_SLOT_SHIFT         0  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN3_START_SLOT_WIDTH         6  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
+
+/*
+ * R781 (0x30D) - AIF1TX Channel 4 Configuration
+ */
+#define WM8915_AIF1TX_CHAN4_DAT_INV             0x8000  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8915_AIF1TX_CHAN4_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8915_AIF1TX_CHAN4_DAT_INV_SHIFT           15  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8915_AIF1TX_CHAN4_DAT_INV_WIDTH            1  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8915_AIF1TX_CHAN4_SPACING_MASK        0x7E00  /* AIF1TX_CHAN4_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN4_SPACING_SHIFT            9  /* AIF1TX_CHAN4_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN4_SPACING_WIDTH            6  /* AIF1TX_CHAN4_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN4_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN4_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN4_SLOTS_SHIFT              6  /* AIF1TX_CHAN4_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN4_SLOTS_WIDTH              3  /* AIF1TX_CHAN4_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN4_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN4_START_SLOT_SHIFT         0  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN4_START_SLOT_WIDTH         6  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
+
+/*
+ * R782 (0x30E) - AIF1TX Channel 5 Configuration
+ */
+#define WM8915_AIF1TX_CHAN5_DAT_INV             0x8000  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8915_AIF1TX_CHAN5_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8915_AIF1TX_CHAN5_DAT_INV_SHIFT           15  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8915_AIF1TX_CHAN5_DAT_INV_WIDTH            1  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8915_AIF1TX_CHAN5_SPACING_MASK        0x7E00  /* AIF1TX_CHAN5_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN5_SPACING_SHIFT            9  /* AIF1TX_CHAN5_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN5_SPACING_WIDTH            6  /* AIF1TX_CHAN5_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN5_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN5_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN5_SLOTS_SHIFT              6  /* AIF1TX_CHAN5_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN5_SLOTS_WIDTH              3  /* AIF1TX_CHAN5_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN5_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN5_START_SLOT_SHIFT         0  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN5_START_SLOT_WIDTH         6  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
+
+/*
+ * R783 (0x30F) - AIF1RX Channel 0 Configuration
+ */
+#define WM8915_AIF1RX_CHAN0_DAT_INV             0x8000  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8915_AIF1RX_CHAN0_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8915_AIF1RX_CHAN0_DAT_INV_SHIFT           15  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8915_AIF1RX_CHAN0_DAT_INV_WIDTH            1  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8915_AIF1RX_CHAN0_SPACING_MASK        0x7E00  /* AIF1RX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN0_SPACING_SHIFT            9  /* AIF1RX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN0_SPACING_WIDTH            6  /* AIF1RX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN0_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN0_SLOTS_SHIFT              6  /* AIF1RX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN0_SLOTS_WIDTH              3  /* AIF1RX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN0_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN0_START_SLOT_SHIFT         0  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN0_START_SLOT_WIDTH         6  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R784 (0x310) - AIF1RX Channel 1 Configuration
+ */
+#define WM8915_AIF1RX_CHAN1_DAT_INV             0x8000  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8915_AIF1RX_CHAN1_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8915_AIF1RX_CHAN1_DAT_INV_SHIFT           15  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8915_AIF1RX_CHAN1_DAT_INV_WIDTH            1  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8915_AIF1RX_CHAN1_SPACING_MASK        0x7E00  /* AIF1RX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN1_SPACING_SHIFT            9  /* AIF1RX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN1_SPACING_WIDTH            6  /* AIF1RX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN1_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN1_SLOTS_SHIFT              6  /* AIF1RX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN1_SLOTS_WIDTH              3  /* AIF1RX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN1_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN1_START_SLOT_SHIFT         0  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN1_START_SLOT_WIDTH         6  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R785 (0x311) - AIF1RX Channel 2 Configuration
+ */
+#define WM8915_AIF1RX_CHAN2_DAT_INV             0x8000  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8915_AIF1RX_CHAN2_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8915_AIF1RX_CHAN2_DAT_INV_SHIFT           15  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8915_AIF1RX_CHAN2_DAT_INV_WIDTH            1  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8915_AIF1RX_CHAN2_SPACING_MASK        0x7E00  /* AIF1RX_CHAN2_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN2_SPACING_SHIFT            9  /* AIF1RX_CHAN2_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN2_SPACING_WIDTH            6  /* AIF1RX_CHAN2_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN2_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN2_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN2_SLOTS_SHIFT              6  /* AIF1RX_CHAN2_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN2_SLOTS_WIDTH              3  /* AIF1RX_CHAN2_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN2_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN2_START_SLOT_SHIFT         0  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN2_START_SLOT_WIDTH         6  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
+
+/*
+ * R786 (0x312) - AIF1RX Channel 3 Configuration
+ */
+#define WM8915_AIF1RX_CHAN3_DAT_INV             0x8000  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8915_AIF1RX_CHAN3_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8915_AIF1RX_CHAN3_DAT_INV_SHIFT           15  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8915_AIF1RX_CHAN3_DAT_INV_WIDTH            1  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8915_AIF1RX_CHAN3_SPACING_MASK        0x7E00  /* AIF1RX_CHAN3_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN3_SPACING_SHIFT            9  /* AIF1RX_CHAN3_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN3_SPACING_WIDTH            6  /* AIF1RX_CHAN3_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN3_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN3_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN3_SLOTS_SHIFT              6  /* AIF1RX_CHAN3_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN3_SLOTS_WIDTH              3  /* AIF1RX_CHAN3_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN3_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN3_START_SLOT_SHIFT         0  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN3_START_SLOT_WIDTH         6  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
+
+/*
+ * R787 (0x313) - AIF1RX Channel 4 Configuration
+ */
+#define WM8915_AIF1RX_CHAN4_DAT_INV             0x8000  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8915_AIF1RX_CHAN4_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8915_AIF1RX_CHAN4_DAT_INV_SHIFT           15  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8915_AIF1RX_CHAN4_DAT_INV_WIDTH            1  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8915_AIF1RX_CHAN4_SPACING_MASK        0x7E00  /* AIF1RX_CHAN4_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN4_SPACING_SHIFT            9  /* AIF1RX_CHAN4_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN4_SPACING_WIDTH            6  /* AIF1RX_CHAN4_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN4_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN4_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN4_SLOTS_SHIFT              6  /* AIF1RX_CHAN4_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN4_SLOTS_WIDTH              3  /* AIF1RX_CHAN4_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN4_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN4_START_SLOT_SHIFT         0  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN4_START_SLOT_WIDTH         6  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
+
+/*
+ * R788 (0x314) - AIF1RX Channel 5 Configuration
+ */
+#define WM8915_AIF1RX_CHAN5_DAT_INV             0x8000  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8915_AIF1RX_CHAN5_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8915_AIF1RX_CHAN5_DAT_INV_SHIFT           15  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8915_AIF1RX_CHAN5_DAT_INV_WIDTH            1  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8915_AIF1RX_CHAN5_SPACING_MASK        0x7E00  /* AIF1RX_CHAN5_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN5_SPACING_SHIFT            9  /* AIF1RX_CHAN5_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN5_SPACING_WIDTH            6  /* AIF1RX_CHAN5_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN5_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN5_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN5_SLOTS_SHIFT              6  /* AIF1RX_CHAN5_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN5_SLOTS_WIDTH              3  /* AIF1RX_CHAN5_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN5_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN5_START_SLOT_SHIFT         0  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN5_START_SLOT_WIDTH         6  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
+
+/*
+ * R789 (0x315) - AIF1RX Mono Configuration
+ */
+#define WM8915_AIF1RX_CHAN4_MONO_MODE           0x0004  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8915_AIF1RX_CHAN4_MONO_MODE_MASK      0x0004  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8915_AIF1RX_CHAN4_MONO_MODE_SHIFT          2  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8915_AIF1RX_CHAN4_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8915_AIF1RX_CHAN2_MONO_MODE           0x0002  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8915_AIF1RX_CHAN2_MONO_MODE_MASK      0x0002  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8915_AIF1RX_CHAN2_MONO_MODE_SHIFT          1  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8915_AIF1RX_CHAN2_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8915_AIF1RX_CHAN0_MONO_MODE           0x0001  /* AIF1RX_CHAN0_MONO_MODE */
+#define WM8915_AIF1RX_CHAN0_MONO_MODE_MASK      0x0001  /* AIF1RX_CHAN0_MONO_MODE */
+#define WM8915_AIF1RX_CHAN0_MONO_MODE_SHIFT          0  /* AIF1RX_CHAN0_MONO_MODE */
+#define WM8915_AIF1RX_CHAN0_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN0_MONO_MODE */
+
+/*
+ * R794 (0x31A) - AIF1TX Test
+ */
+#define WM8915_AIF1TX45_DITHER_ENA              0x0004  /* AIF1TX45_DITHER_ENA */
+#define WM8915_AIF1TX45_DITHER_ENA_MASK         0x0004  /* AIF1TX45_DITHER_ENA */
+#define WM8915_AIF1TX45_DITHER_ENA_SHIFT             2  /* AIF1TX45_DITHER_ENA */
+#define WM8915_AIF1TX45_DITHER_ENA_WIDTH             1  /* AIF1TX45_DITHER_ENA */
+#define WM8915_AIF1TX23_DITHER_ENA              0x0002  /* AIF1TX23_DITHER_ENA */
+#define WM8915_AIF1TX23_DITHER_ENA_MASK         0x0002  /* AIF1TX23_DITHER_ENA */
+#define WM8915_AIF1TX23_DITHER_ENA_SHIFT             1  /* AIF1TX23_DITHER_ENA */
+#define WM8915_AIF1TX23_DITHER_ENA_WIDTH             1  /* AIF1TX23_DITHER_ENA */
+#define WM8915_AIF1TX01_DITHER_ENA              0x0001  /* AIF1TX01_DITHER_ENA */
+#define WM8915_AIF1TX01_DITHER_ENA_MASK         0x0001  /* AIF1TX01_DITHER_ENA */
+#define WM8915_AIF1TX01_DITHER_ENA_SHIFT             0  /* AIF1TX01_DITHER_ENA */
+#define WM8915_AIF1TX01_DITHER_ENA_WIDTH             1  /* AIF1TX01_DITHER_ENA */
+
+/*
+ * R800 (0x320) - AIF2 Control
+ */
+#define WM8915_AIF2_TRI                         0x0004  /* AIF2_TRI */
+#define WM8915_AIF2_TRI_MASK                    0x0004  /* AIF2_TRI */
+#define WM8915_AIF2_TRI_SHIFT                        2  /* AIF2_TRI */
+#define WM8915_AIF2_TRI_WIDTH                        1  /* AIF2_TRI */
+#define WM8915_AIF2_FMT_MASK                    0x0003  /* AIF2_FMT - [1:0] */
+#define WM8915_AIF2_FMT_SHIFT                        0  /* AIF2_FMT - [1:0] */
+#define WM8915_AIF2_FMT_WIDTH                        2  /* AIF2_FMT - [1:0] */
+
+/*
+ * R801 (0x321) - AIF2 BCLK
+ */
+#define WM8915_AIF2_BCLK_INV                    0x0400  /* AIF2_BCLK_INV */
+#define WM8915_AIF2_BCLK_INV_MASK               0x0400  /* AIF2_BCLK_INV */
+#define WM8915_AIF2_BCLK_INV_SHIFT                  10  /* AIF2_BCLK_INV */
+#define WM8915_AIF2_BCLK_INV_WIDTH                   1  /* AIF2_BCLK_INV */
+#define WM8915_AIF2_BCLK_FRC                    0x0200  /* AIF2_BCLK_FRC */
+#define WM8915_AIF2_BCLK_FRC_MASK               0x0200  /* AIF2_BCLK_FRC */
+#define WM8915_AIF2_BCLK_FRC_SHIFT                   9  /* AIF2_BCLK_FRC */
+#define WM8915_AIF2_BCLK_FRC_WIDTH                   1  /* AIF2_BCLK_FRC */
+#define WM8915_AIF2_BCLK_MSTR                   0x0100  /* AIF2_BCLK_MSTR */
+#define WM8915_AIF2_BCLK_MSTR_MASK              0x0100  /* AIF2_BCLK_MSTR */
+#define WM8915_AIF2_BCLK_MSTR_SHIFT                  8  /* AIF2_BCLK_MSTR */
+#define WM8915_AIF2_BCLK_MSTR_WIDTH                  1  /* AIF2_BCLK_MSTR */
+#define WM8915_AIF2_BCLK_DIV_MASK               0x000F  /* AIF2_BCLK_DIV - [3:0] */
+#define WM8915_AIF2_BCLK_DIV_SHIFT                   0  /* AIF2_BCLK_DIV - [3:0] */
+#define WM8915_AIF2_BCLK_DIV_WIDTH                   4  /* AIF2_BCLK_DIV - [3:0] */
+
+/*
+ * R802 (0x322) - AIF2 TX LRCLK(1)
+ */
+#define WM8915_AIF2TX_RATE_MASK                 0x07FF  /* AIF2TX_RATE - [10:0] */
+#define WM8915_AIF2TX_RATE_SHIFT                     0  /* AIF2TX_RATE - [10:0] */
+#define WM8915_AIF2TX_RATE_WIDTH                    11  /* AIF2TX_RATE - [10:0] */
+
+/*
+ * R803 (0x323) - AIF2 TX LRCLK(2)
+ */
+#define WM8915_AIF2TX_LRCLK_MODE                0x0008  /* AIF2TX_LRCLK_MODE */
+#define WM8915_AIF2TX_LRCLK_MODE_MASK           0x0008  /* AIF2TX_LRCLK_MODE */
+#define WM8915_AIF2TX_LRCLK_MODE_SHIFT               3  /* AIF2TX_LRCLK_MODE */
+#define WM8915_AIF2TX_LRCLK_MODE_WIDTH               1  /* AIF2TX_LRCLK_MODE */
+#define WM8915_AIF2TX_LRCLK_INV                 0x0004  /* AIF2TX_LRCLK_INV */
+#define WM8915_AIF2TX_LRCLK_INV_MASK            0x0004  /* AIF2TX_LRCLK_INV */
+#define WM8915_AIF2TX_LRCLK_INV_SHIFT                2  /* AIF2TX_LRCLK_INV */
+#define WM8915_AIF2TX_LRCLK_INV_WIDTH                1  /* AIF2TX_LRCLK_INV */
+#define WM8915_AIF2TX_LRCLK_FRC                 0x0002  /* AIF2TX_LRCLK_FRC */
+#define WM8915_AIF2TX_LRCLK_FRC_MASK            0x0002  /* AIF2TX_LRCLK_FRC */
+#define WM8915_AIF2TX_LRCLK_FRC_SHIFT                1  /* AIF2TX_LRCLK_FRC */
+#define WM8915_AIF2TX_LRCLK_FRC_WIDTH                1  /* AIF2TX_LRCLK_FRC */
+#define WM8915_AIF2TX_LRCLK_MSTR                0x0001  /* AIF2TX_LRCLK_MSTR */
+#define WM8915_AIF2TX_LRCLK_MSTR_MASK           0x0001  /* AIF2TX_LRCLK_MSTR */
+#define WM8915_AIF2TX_LRCLK_MSTR_SHIFT               0  /* AIF2TX_LRCLK_MSTR */
+#define WM8915_AIF2TX_LRCLK_MSTR_WIDTH               1  /* AIF2TX_LRCLK_MSTR */
+
+/*
+ * R804 (0x324) - AIF2 RX LRCLK(1)
+ */
+#define WM8915_AIF2RX_RATE_MASK                 0x07FF  /* AIF2RX_RATE - [10:0] */
+#define WM8915_AIF2RX_RATE_SHIFT                     0  /* AIF2RX_RATE - [10:0] */
+#define WM8915_AIF2RX_RATE_WIDTH                    11  /* AIF2RX_RATE - [10:0] */
+
+/*
+ * R805 (0x325) - AIF2 RX LRCLK(2)
+ */
+#define WM8915_AIF2RX_LRCLK_INV                 0x0004  /* AIF2RX_LRCLK_INV */
+#define WM8915_AIF2RX_LRCLK_INV_MASK            0x0004  /* AIF2RX_LRCLK_INV */
+#define WM8915_AIF2RX_LRCLK_INV_SHIFT                2  /* AIF2RX_LRCLK_INV */
+#define WM8915_AIF2RX_LRCLK_INV_WIDTH                1  /* AIF2RX_LRCLK_INV */
+#define WM8915_AIF2RX_LRCLK_FRC                 0x0002  /* AIF2RX_LRCLK_FRC */
+#define WM8915_AIF2RX_LRCLK_FRC_MASK            0x0002  /* AIF2RX_LRCLK_FRC */
+#define WM8915_AIF2RX_LRCLK_FRC_SHIFT                1  /* AIF2RX_LRCLK_FRC */
+#define WM8915_AIF2RX_LRCLK_FRC_WIDTH                1  /* AIF2RX_LRCLK_FRC */
+#define WM8915_AIF2RX_LRCLK_MSTR                0x0001  /* AIF2RX_LRCLK_MSTR */
+#define WM8915_AIF2RX_LRCLK_MSTR_MASK           0x0001  /* AIF2RX_LRCLK_MSTR */
+#define WM8915_AIF2RX_LRCLK_MSTR_SHIFT               0  /* AIF2RX_LRCLK_MSTR */
+#define WM8915_AIF2RX_LRCLK_MSTR_WIDTH               1  /* AIF2RX_LRCLK_MSTR */
+
+/*
+ * R806 (0x326) - AIF2TX Data Configuration (1)
+ */
+#define WM8915_AIF2TX_WL_MASK                   0xFF00  /* AIF2TX_WL - [15:8] */
+#define WM8915_AIF2TX_WL_SHIFT                       8  /* AIF2TX_WL - [15:8] */
+#define WM8915_AIF2TX_WL_WIDTH                       8  /* AIF2TX_WL - [15:8] */
+#define WM8915_AIF2TX_SLOT_LEN_MASK             0x00FF  /* AIF2TX_SLOT_LEN - [7:0] */
+#define WM8915_AIF2TX_SLOT_LEN_SHIFT                 0  /* AIF2TX_SLOT_LEN - [7:0] */
+#define WM8915_AIF2TX_SLOT_LEN_WIDTH                 8  /* AIF2TX_SLOT_LEN - [7:0] */
+
+/*
+ * R807 (0x327) - AIF2TX Data Configuration (2)
+ */
+#define WM8915_AIF2TX_DAT_TRI                   0x0001  /* AIF2TX_DAT_TRI */
+#define WM8915_AIF2TX_DAT_TRI_MASK              0x0001  /* AIF2TX_DAT_TRI */
+#define WM8915_AIF2TX_DAT_TRI_SHIFT                  0  /* AIF2TX_DAT_TRI */
+#define WM8915_AIF2TX_DAT_TRI_WIDTH                  1  /* AIF2TX_DAT_TRI */
+
+/*
+ * R808 (0x328) - AIF2RX Data Configuration
+ */
+#define WM8915_AIF2RX_WL_MASK                   0xFF00  /* AIF2RX_WL - [15:8] */
+#define WM8915_AIF2RX_WL_SHIFT                       8  /* AIF2RX_WL - [15:8] */
+#define WM8915_AIF2RX_WL_WIDTH                       8  /* AIF2RX_WL - [15:8] */
+#define WM8915_AIF2RX_SLOT_LEN_MASK             0x00FF  /* AIF2RX_SLOT_LEN - [7:0] */
+#define WM8915_AIF2RX_SLOT_LEN_SHIFT                 0  /* AIF2RX_SLOT_LEN - [7:0] */
+#define WM8915_AIF2RX_SLOT_LEN_WIDTH                 8  /* AIF2RX_SLOT_LEN - [7:0] */
+
+/*
+ * R809 (0x329) - AIF2TX Channel 0 Configuration
+ */
+#define WM8915_AIF2TX_CHAN0_DAT_INV             0x8000  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8915_AIF2TX_CHAN0_DAT_INV_MASK        0x8000  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8915_AIF2TX_CHAN0_DAT_INV_SHIFT           15  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8915_AIF2TX_CHAN0_DAT_INV_WIDTH            1  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8915_AIF2TX_CHAN0_SPACING_MASK        0x7E00  /* AIF2TX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF2TX_CHAN0_SPACING_SHIFT            9  /* AIF2TX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF2TX_CHAN0_SPACING_WIDTH            6  /* AIF2TX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF2TX_CHAN0_SLOTS_MASK          0x01C0  /* AIF2TX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF2TX_CHAN0_SLOTS_SHIFT              6  /* AIF2TX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF2TX_CHAN0_SLOTS_WIDTH              3  /* AIF2TX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF2TX_CHAN0_START_SLOT_MASK     0x003F  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF2TX_CHAN0_START_SLOT_SHIFT         0  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF2TX_CHAN0_START_SLOT_WIDTH         6  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R810 (0x32A) - AIF2TX Channel 1 Configuration
+ */
+#define WM8915_AIF2TX_CHAN1_DAT_INV             0x8000  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8915_AIF2TX_CHAN1_DAT_INV_MASK        0x8000  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8915_AIF2TX_CHAN1_DAT_INV_SHIFT           15  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8915_AIF2TX_CHAN1_DAT_INV_WIDTH            1  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8915_AIF2TX_CHAN1_SPACING_MASK        0x7E00  /* AIF2TX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF2TX_CHAN1_SPACING_SHIFT            9  /* AIF2TX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF2TX_CHAN1_SPACING_WIDTH            6  /* AIF2TX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF2TX_CHAN1_SLOTS_MASK          0x01C0  /* AIF2TX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF2TX_CHAN1_SLOTS_SHIFT              6  /* AIF2TX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF2TX_CHAN1_SLOTS_WIDTH              3  /* AIF2TX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF2TX_CHAN1_START_SLOT_MASK     0x003F  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF2TX_CHAN1_START_SLOT_SHIFT         0  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF2TX_CHAN1_START_SLOT_WIDTH         6  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R811 (0x32B) - AIF2RX Channel 0 Configuration
+ */
+#define WM8915_AIF2RX_CHAN0_DAT_INV             0x8000  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8915_AIF2RX_CHAN0_DAT_INV_MASK        0x8000  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8915_AIF2RX_CHAN0_DAT_INV_SHIFT           15  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8915_AIF2RX_CHAN0_DAT_INV_WIDTH            1  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8915_AIF2RX_CHAN0_SPACING_MASK        0x7E00  /* AIF2RX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF2RX_CHAN0_SPACING_SHIFT            9  /* AIF2RX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF2RX_CHAN0_SPACING_WIDTH            6  /* AIF2RX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF2RX_CHAN0_SLOTS_MASK          0x01C0  /* AIF2RX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF2RX_CHAN0_SLOTS_SHIFT              6  /* AIF2RX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF2RX_CHAN0_SLOTS_WIDTH              3  /* AIF2RX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF2RX_CHAN0_START_SLOT_MASK     0x003F  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF2RX_CHAN0_START_SLOT_SHIFT         0  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF2RX_CHAN0_START_SLOT_WIDTH         6  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R812 (0x32C) - AIF2RX Channel 1 Configuration
+ */
+#define WM8915_AIF2RX_CHAN1_DAT_INV             0x8000  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8915_AIF2RX_CHAN1_DAT_INV_MASK        0x8000  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8915_AIF2RX_CHAN1_DAT_INV_SHIFT           15  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8915_AIF2RX_CHAN1_DAT_INV_WIDTH            1  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8915_AIF2RX_CHAN1_SPACING_MASK        0x7E00  /* AIF2RX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF2RX_CHAN1_SPACING_SHIFT            9  /* AIF2RX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF2RX_CHAN1_SPACING_WIDTH            6  /* AIF2RX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF2RX_CHAN1_SLOTS_MASK          0x01C0  /* AIF2RX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF2RX_CHAN1_SLOTS_SHIFT              6  /* AIF2RX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF2RX_CHAN1_SLOTS_WIDTH              3  /* AIF2RX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF2RX_CHAN1_START_SLOT_MASK     0x003F  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF2RX_CHAN1_START_SLOT_SHIFT         0  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF2RX_CHAN1_START_SLOT_WIDTH         6  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R813 (0x32D) - AIF2RX Mono Configuration
+ */
+#define WM8915_AIF2RX_CHAN0_MONO_MODE           0x0001  /* AIF2RX_CHAN0_MONO_MODE */
+#define WM8915_AIF2RX_CHAN0_MONO_MODE_MASK      0x0001  /* AIF2RX_CHAN0_MONO_MODE */
+#define WM8915_AIF2RX_CHAN0_MONO_MODE_SHIFT          0  /* AIF2RX_CHAN0_MONO_MODE */
+#define WM8915_AIF2RX_CHAN0_MONO_MODE_WIDTH          1  /* AIF2RX_CHAN0_MONO_MODE */
+
+/*
+ * R815 (0x32F) - AIF2TX Test
+ */
+#define WM8915_AIF2TX_DITHER_ENA                0x0001  /* AIF2TX_DITHER_ENA */
+#define WM8915_AIF2TX_DITHER_ENA_MASK           0x0001  /* AIF2TX_DITHER_ENA */
+#define WM8915_AIF2TX_DITHER_ENA_SHIFT               0  /* AIF2TX_DITHER_ENA */
+#define WM8915_AIF2TX_DITHER_ENA_WIDTH               1  /* AIF2TX_DITHER_ENA */
+
+/*
+ * R1024 (0x400) - DSP1 TX Left Volume
+ */
+#define WM8915_DSP1TX_VU                        0x0100  /* DSP1TX_VU */
+#define WM8915_DSP1TX_VU_MASK                   0x0100  /* DSP1TX_VU */
+#define WM8915_DSP1TX_VU_SHIFT                       8  /* DSP1TX_VU */
+#define WM8915_DSP1TX_VU_WIDTH                       1  /* DSP1TX_VU */
+#define WM8915_DSP1TXL_VOL_MASK                 0x00FF  /* DSP1TXL_VOL - [7:0] */
+#define WM8915_DSP1TXL_VOL_SHIFT                     0  /* DSP1TXL_VOL - [7:0] */
+#define WM8915_DSP1TXL_VOL_WIDTH                     8  /* DSP1TXL_VOL - [7:0] */
+
+/*
+ * R1025 (0x401) - DSP1 TX Right Volume
+ */
+#define WM8915_DSP1TX_VU                        0x0100  /* DSP1TX_VU */
+#define WM8915_DSP1TX_VU_MASK                   0x0100  /* DSP1TX_VU */
+#define WM8915_DSP1TX_VU_SHIFT                       8  /* DSP1TX_VU */
+#define WM8915_DSP1TX_VU_WIDTH                       1  /* DSP1TX_VU */
+#define WM8915_DSP1TXR_VOL_MASK                 0x00FF  /* DSP1TXR_VOL - [7:0] */
+#define WM8915_DSP1TXR_VOL_SHIFT                     0  /* DSP1TXR_VOL - [7:0] */
+#define WM8915_DSP1TXR_VOL_WIDTH                     8  /* DSP1TXR_VOL - [7:0] */
+
+/*
+ * R1026 (0x402) - DSP1 RX Left Volume
+ */
+#define WM8915_DSP1RX_VU                        0x0100  /* DSP1RX_VU */
+#define WM8915_DSP1RX_VU_MASK                   0x0100  /* DSP1RX_VU */
+#define WM8915_DSP1RX_VU_SHIFT                       8  /* DSP1RX_VU */
+#define WM8915_DSP1RX_VU_WIDTH                       1  /* DSP1RX_VU */
+#define WM8915_DSP1RXL_VOL_MASK                 0x00FF  /* DSP1RXL_VOL - [7:0] */
+#define WM8915_DSP1RXL_VOL_SHIFT                     0  /* DSP1RXL_VOL - [7:0] */
+#define WM8915_DSP1RXL_VOL_WIDTH                     8  /* DSP1RXL_VOL - [7:0] */
+
+/*
+ * R1027 (0x403) - DSP1 RX Right Volume
+ */
+#define WM8915_DSP1RX_VU                        0x0100  /* DSP1RX_VU */
+#define WM8915_DSP1RX_VU_MASK                   0x0100  /* DSP1RX_VU */
+#define WM8915_DSP1RX_VU_SHIFT                       8  /* DSP1RX_VU */
+#define WM8915_DSP1RX_VU_WIDTH                       1  /* DSP1RX_VU */
+#define WM8915_DSP1RXR_VOL_MASK                 0x00FF  /* DSP1RXR_VOL - [7:0] */
+#define WM8915_DSP1RXR_VOL_SHIFT                     0  /* DSP1RXR_VOL - [7:0] */
+#define WM8915_DSP1RXR_VOL_WIDTH                     8  /* DSP1RXR_VOL - [7:0] */
+
+/*
+ * R1040 (0x410) - DSP1 TX Filters
+ */
+#define WM8915_DSP1TX_NF                        0x2000  /* DSP1TX_NF */
+#define WM8915_DSP1TX_NF_MASK                   0x2000  /* DSP1TX_NF */
+#define WM8915_DSP1TX_NF_SHIFT                      13  /* DSP1TX_NF */
+#define WM8915_DSP1TX_NF_WIDTH                       1  /* DSP1TX_NF */
+#define WM8915_DSP1TXL_HPF                      0x1000  /* DSP1TXL_HPF */
+#define WM8915_DSP1TXL_HPF_MASK                 0x1000  /* DSP1TXL_HPF */
+#define WM8915_DSP1TXL_HPF_SHIFT                    12  /* DSP1TXL_HPF */
+#define WM8915_DSP1TXL_HPF_WIDTH                     1  /* DSP1TXL_HPF */
+#define WM8915_DSP1TXR_HPF                      0x0800  /* DSP1TXR_HPF */
+#define WM8915_DSP1TXR_HPF_MASK                 0x0800  /* DSP1TXR_HPF */
+#define WM8915_DSP1TXR_HPF_SHIFT                    11  /* DSP1TXR_HPF */
+#define WM8915_DSP1TXR_HPF_WIDTH                     1  /* DSP1TXR_HPF */
+#define WM8915_DSP1TX_HPF_MODE_MASK             0x0018  /* DSP1TX_HPF_MODE - [4:3] */
+#define WM8915_DSP1TX_HPF_MODE_SHIFT                 3  /* DSP1TX_HPF_MODE - [4:3] */
+#define WM8915_DSP1TX_HPF_MODE_WIDTH                 2  /* DSP1TX_HPF_MODE - [4:3] */
+#define WM8915_DSP1TX_HPF_CUT_MASK              0x0007  /* DSP1TX_HPF_CUT - [2:0] */
+#define WM8915_DSP1TX_HPF_CUT_SHIFT                  0  /* DSP1TX_HPF_CUT - [2:0] */
+#define WM8915_DSP1TX_HPF_CUT_WIDTH                  3  /* DSP1TX_HPF_CUT - [2:0] */
+
+/*
+ * R1056 (0x420) - DSP1 RX Filters (1)
+ */
+#define WM8915_DSP1RX_MUTE                      0x0200  /* DSP1RX_MUTE */
+#define WM8915_DSP1RX_MUTE_MASK                 0x0200  /* DSP1RX_MUTE */
+#define WM8915_DSP1RX_MUTE_SHIFT                     9  /* DSP1RX_MUTE */
+#define WM8915_DSP1RX_MUTE_WIDTH                     1  /* DSP1RX_MUTE */
+#define WM8915_DSP1RX_MONO                      0x0080  /* DSP1RX_MONO */
+#define WM8915_DSP1RX_MONO_MASK                 0x0080  /* DSP1RX_MONO */
+#define WM8915_DSP1RX_MONO_SHIFT                     7  /* DSP1RX_MONO */
+#define WM8915_DSP1RX_MONO_WIDTH                     1  /* DSP1RX_MONO */
+#define WM8915_DSP1RX_MUTERATE                  0x0020  /* DSP1RX_MUTERATE */
+#define WM8915_DSP1RX_MUTERATE_MASK             0x0020  /* DSP1RX_MUTERATE */
+#define WM8915_DSP1RX_MUTERATE_SHIFT                 5  /* DSP1RX_MUTERATE */
+#define WM8915_DSP1RX_MUTERATE_WIDTH                 1  /* DSP1RX_MUTERATE */
+#define WM8915_DSP1RX_UNMUTE_RAMP               0x0010  /* DSP1RX_UNMUTE_RAMP */
+#define WM8915_DSP1RX_UNMUTE_RAMP_MASK          0x0010  /* DSP1RX_UNMUTE_RAMP */
+#define WM8915_DSP1RX_UNMUTE_RAMP_SHIFT              4  /* DSP1RX_UNMUTE_RAMP */
+#define WM8915_DSP1RX_UNMUTE_RAMP_WIDTH              1  /* DSP1RX_UNMUTE_RAMP */
+
+/*
+ * R1057 (0x421) - DSP1 RX Filters (2)
+ */
+#define WM8915_DSP1RX_3D_GAIN_MASK              0x3E00  /* DSP1RX_3D_GAIN - [13:9] */
+#define WM8915_DSP1RX_3D_GAIN_SHIFT                  9  /* DSP1RX_3D_GAIN - [13:9] */
+#define WM8915_DSP1RX_3D_GAIN_WIDTH                  5  /* DSP1RX_3D_GAIN - [13:9] */
+#define WM8915_DSP1RX_3D_ENA                    0x0100  /* DSP1RX_3D_ENA */
+#define WM8915_DSP1RX_3D_ENA_MASK               0x0100  /* DSP1RX_3D_ENA */
+#define WM8915_DSP1RX_3D_ENA_SHIFT                   8  /* DSP1RX_3D_ENA */
+#define WM8915_DSP1RX_3D_ENA_WIDTH                   1  /* DSP1RX_3D_ENA */
+
+/*
+ * R1088 (0x440) - DSP1 DRC (1)
+ */
+#define WM8915_DSP1DRC_SIG_DET_RMS_MASK         0xF800  /* DSP1DRC_SIG_DET_RMS - [15:11] */
+#define WM8915_DSP1DRC_SIG_DET_RMS_SHIFT            11  /* DSP1DRC_SIG_DET_RMS - [15:11] */
+#define WM8915_DSP1DRC_SIG_DET_RMS_WIDTH             5  /* DSP1DRC_SIG_DET_RMS - [15:11] */
+#define WM8915_DSP1DRC_SIG_DET_PK_MASK          0x0600  /* DSP1DRC_SIG_DET_PK - [10:9] */
+#define WM8915_DSP1DRC_SIG_DET_PK_SHIFT              9  /* DSP1DRC_SIG_DET_PK - [10:9] */
+#define WM8915_DSP1DRC_SIG_DET_PK_WIDTH              2  /* DSP1DRC_SIG_DET_PK - [10:9] */
+#define WM8915_DSP1DRC_NG_ENA                   0x0100  /* DSP1DRC_NG_ENA */
+#define WM8915_DSP1DRC_NG_ENA_MASK              0x0100  /* DSP1DRC_NG_ENA */
+#define WM8915_DSP1DRC_NG_ENA_SHIFT                  8  /* DSP1DRC_NG_ENA */
+#define WM8915_DSP1DRC_NG_ENA_WIDTH                  1  /* DSP1DRC_NG_ENA */
+#define WM8915_DSP1DRC_SIG_DET_MODE             0x0080  /* DSP1DRC_SIG_DET_MODE */
+#define WM8915_DSP1DRC_SIG_DET_MODE_MASK        0x0080  /* DSP1DRC_SIG_DET_MODE */
+#define WM8915_DSP1DRC_SIG_DET_MODE_SHIFT            7  /* DSP1DRC_SIG_DET_MODE */
+#define WM8915_DSP1DRC_SIG_DET_MODE_WIDTH            1  /* DSP1DRC_SIG_DET_MODE */
+#define WM8915_DSP1DRC_SIG_DET                  0x0040  /* DSP1DRC_SIG_DET */
+#define WM8915_DSP1DRC_SIG_DET_MASK             0x0040  /* DSP1DRC_SIG_DET */
+#define WM8915_DSP1DRC_SIG_DET_SHIFT                 6  /* DSP1DRC_SIG_DET */
+#define WM8915_DSP1DRC_SIG_DET_WIDTH                 1  /* DSP1DRC_SIG_DET */
+#define WM8915_DSP1DRC_KNEE2_OP_ENA             0x0020  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8915_DSP1DRC_KNEE2_OP_ENA_MASK        0x0020  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8915_DSP1DRC_KNEE2_OP_ENA_SHIFT            5  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8915_DSP1DRC_KNEE2_OP_ENA_WIDTH            1  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8915_DSP1DRC_QR                       0x0010  /* DSP1DRC_QR */
+#define WM8915_DSP1DRC_QR_MASK                  0x0010  /* DSP1DRC_QR */
+#define WM8915_DSP1DRC_QR_SHIFT                      4  /* DSP1DRC_QR */
+#define WM8915_DSP1DRC_QR_WIDTH                      1  /* DSP1DRC_QR */
+#define WM8915_DSP1DRC_ANTICLIP                 0x0008  /* DSP1DRC_ANTICLIP */
+#define WM8915_DSP1DRC_ANTICLIP_MASK            0x0008  /* DSP1DRC_ANTICLIP */
+#define WM8915_DSP1DRC_ANTICLIP_SHIFT                3  /* DSP1DRC_ANTICLIP */
+#define WM8915_DSP1DRC_ANTICLIP_WIDTH                1  /* DSP1DRC_ANTICLIP */
+#define WM8915_DSP1RX_DRC_ENA                   0x0004  /* DSP1RX_DRC_ENA */
+#define WM8915_DSP1RX_DRC_ENA_MASK              0x0004  /* DSP1RX_DRC_ENA */
+#define WM8915_DSP1RX_DRC_ENA_SHIFT                  2  /* DSP1RX_DRC_ENA */
+#define WM8915_DSP1RX_DRC_ENA_WIDTH                  1  /* DSP1RX_DRC_ENA */
+#define WM8915_DSP1TXL_DRC_ENA                  0x0002  /* DSP1TXL_DRC_ENA */
+#define WM8915_DSP1TXL_DRC_ENA_MASK             0x0002  /* DSP1TXL_DRC_ENA */
+#define WM8915_DSP1TXL_DRC_ENA_SHIFT                 1  /* DSP1TXL_DRC_ENA */
+#define WM8915_DSP1TXL_DRC_ENA_WIDTH                 1  /* DSP1TXL_DRC_ENA */
+#define WM8915_DSP1TXR_DRC_ENA                  0x0001  /* DSP1TXR_DRC_ENA */
+#define WM8915_DSP1TXR_DRC_ENA_MASK             0x0001  /* DSP1TXR_DRC_ENA */
+#define WM8915_DSP1TXR_DRC_ENA_SHIFT                 0  /* DSP1TXR_DRC_ENA */
+#define WM8915_DSP1TXR_DRC_ENA_WIDTH                 1  /* DSP1TXR_DRC_ENA */
+
+/*
+ * R1089 (0x441) - DSP1 DRC (2)
+ */
+#define WM8915_DSP1DRC_ATK_MASK                 0x1E00  /* DSP1DRC_ATK - [12:9] */
+#define WM8915_DSP1DRC_ATK_SHIFT                     9  /* DSP1DRC_ATK - [12:9] */
+#define WM8915_DSP1DRC_ATK_WIDTH                     4  /* DSP1DRC_ATK - [12:9] */
+#define WM8915_DSP1DRC_DCY_MASK                 0x01E0  /* DSP1DRC_DCY - [8:5] */
+#define WM8915_DSP1DRC_DCY_SHIFT                     5  /* DSP1DRC_DCY - [8:5] */
+#define WM8915_DSP1DRC_DCY_WIDTH                     4  /* DSP1DRC_DCY - [8:5] */
+#define WM8915_DSP1DRC_MINGAIN_MASK             0x001C  /* DSP1DRC_MINGAIN - [4:2] */
+#define WM8915_DSP1DRC_MINGAIN_SHIFT                 2  /* DSP1DRC_MINGAIN - [4:2] */
+#define WM8915_DSP1DRC_MINGAIN_WIDTH                 3  /* DSP1DRC_MINGAIN - [4:2] */
+#define WM8915_DSP1DRC_MAXGAIN_MASK             0x0003  /* DSP1DRC_MAXGAIN - [1:0] */
+#define WM8915_DSP1DRC_MAXGAIN_SHIFT                 0  /* DSP1DRC_MAXGAIN - [1:0] */
+#define WM8915_DSP1DRC_MAXGAIN_WIDTH                 2  /* DSP1DRC_MAXGAIN - [1:0] */
+
+/*
+ * R1090 (0x442) - DSP1 DRC (3)
+ */
+#define WM8915_DSP1DRC_NG_MINGAIN_MASK          0xF000  /* DSP1DRC_NG_MINGAIN - [15:12] */
+#define WM8915_DSP1DRC_NG_MINGAIN_SHIFT             12  /* DSP1DRC_NG_MINGAIN - [15:12] */
+#define WM8915_DSP1DRC_NG_MINGAIN_WIDTH              4  /* DSP1DRC_NG_MINGAIN - [15:12] */
+#define WM8915_DSP1DRC_NG_EXP_MASK              0x0C00  /* DSP1DRC_NG_EXP - [11:10] */
+#define WM8915_DSP1DRC_NG_EXP_SHIFT                 10  /* DSP1DRC_NG_EXP - [11:10] */
+#define WM8915_DSP1DRC_NG_EXP_WIDTH                  2  /* DSP1DRC_NG_EXP - [11:10] */
+#define WM8915_DSP1DRC_QR_THR_MASK              0x0300  /* DSP1DRC_QR_THR - [9:8] */
+#define WM8915_DSP1DRC_QR_THR_SHIFT                  8  /* DSP1DRC_QR_THR - [9:8] */
+#define WM8915_DSP1DRC_QR_THR_WIDTH                  2  /* DSP1DRC_QR_THR - [9:8] */
+#define WM8915_DSP1DRC_QR_DCY_MASK              0x00C0  /* DSP1DRC_QR_DCY - [7:6] */
+#define WM8915_DSP1DRC_QR_DCY_SHIFT                  6  /* DSP1DRC_QR_DCY - [7:6] */
+#define WM8915_DSP1DRC_QR_DCY_WIDTH                  2  /* DSP1DRC_QR_DCY - [7:6] */
+#define WM8915_DSP1DRC_HI_COMP_MASK             0x0038  /* DSP1DRC_HI_COMP - [5:3] */
+#define WM8915_DSP1DRC_HI_COMP_SHIFT                 3  /* DSP1DRC_HI_COMP - [5:3] */
+#define WM8915_DSP1DRC_HI_COMP_WIDTH                 3  /* DSP1DRC_HI_COMP - [5:3] */
+#define WM8915_DSP1DRC_LO_COMP_MASK             0x0007  /* DSP1DRC_LO_COMP - [2:0] */
+#define WM8915_DSP1DRC_LO_COMP_SHIFT                 0  /* DSP1DRC_LO_COMP - [2:0] */
+#define WM8915_DSP1DRC_LO_COMP_WIDTH                 3  /* DSP1DRC_LO_COMP - [2:0] */
+
+/*
+ * R1091 (0x443) - DSP1 DRC (4)
+ */
+#define WM8915_DSP1DRC_KNEE_IP_MASK             0x07E0  /* DSP1DRC_KNEE_IP - [10:5] */
+#define WM8915_DSP1DRC_KNEE_IP_SHIFT                 5  /* DSP1DRC_KNEE_IP - [10:5] */
+#define WM8915_DSP1DRC_KNEE_IP_WIDTH                 6  /* DSP1DRC_KNEE_IP - [10:5] */
+#define WM8915_DSP1DRC_KNEE_OP_MASK             0x001F  /* DSP1DRC_KNEE_OP - [4:0] */
+#define WM8915_DSP1DRC_KNEE_OP_SHIFT                 0  /* DSP1DRC_KNEE_OP - [4:0] */
+#define WM8915_DSP1DRC_KNEE_OP_WIDTH                 5  /* DSP1DRC_KNEE_OP - [4:0] */
+
+/*
+ * R1092 (0x444) - DSP1 DRC (5)
+ */
+#define WM8915_DSP1DRC_KNEE2_IP_MASK            0x03E0  /* DSP1DRC_KNEE2_IP - [9:5] */
+#define WM8915_DSP1DRC_KNEE2_IP_SHIFT                5  /* DSP1DRC_KNEE2_IP - [9:5] */
+#define WM8915_DSP1DRC_KNEE2_IP_WIDTH                5  /* DSP1DRC_KNEE2_IP - [9:5] */
+#define WM8915_DSP1DRC_KNEE2_OP_MASK            0x001F  /* DSP1DRC_KNEE2_OP - [4:0] */
+#define WM8915_DSP1DRC_KNEE2_OP_SHIFT                0  /* DSP1DRC_KNEE2_OP - [4:0] */
+#define WM8915_DSP1DRC_KNEE2_OP_WIDTH                5  /* DSP1DRC_KNEE2_OP - [4:0] */
+
+/*
+ * R1152 (0x480) - DSP1 RX EQ Gains (1)
+ */
+#define WM8915_DSP1RX_EQ_B1_GAIN_MASK           0xF800  /* DSP1RX_EQ_B1_GAIN - [15:11] */
+#define WM8915_DSP1RX_EQ_B1_GAIN_SHIFT              11  /* DSP1RX_EQ_B1_GAIN - [15:11] */
+#define WM8915_DSP1RX_EQ_B1_GAIN_WIDTH               5  /* DSP1RX_EQ_B1_GAIN - [15:11] */
+#define WM8915_DSP1RX_EQ_B2_GAIN_MASK           0x07C0  /* DSP1RX_EQ_B2_GAIN - [10:6] */
+#define WM8915_DSP1RX_EQ_B2_GAIN_SHIFT               6  /* DSP1RX_EQ_B2_GAIN - [10:6] */
+#define WM8915_DSP1RX_EQ_B2_GAIN_WIDTH               5  /* DSP1RX_EQ_B2_GAIN - [10:6] */
+#define WM8915_DSP1RX_EQ_B3_GAIN_MASK           0x003E  /* DSP1RX_EQ_B3_GAIN - [5:1] */
+#define WM8915_DSP1RX_EQ_B3_GAIN_SHIFT               1  /* DSP1RX_EQ_B3_GAIN - [5:1] */
+#define WM8915_DSP1RX_EQ_B3_GAIN_WIDTH               5  /* DSP1RX_EQ_B3_GAIN - [5:1] */
+#define WM8915_DSP1RX_EQ_ENA                    0x0001  /* DSP1RX_EQ_ENA */
+#define WM8915_DSP1RX_EQ_ENA_MASK               0x0001  /* DSP1RX_EQ_ENA */
+#define WM8915_DSP1RX_EQ_ENA_SHIFT                   0  /* DSP1RX_EQ_ENA */
+#define WM8915_DSP1RX_EQ_ENA_WIDTH                   1  /* DSP1RX_EQ_ENA */
+
+/*
+ * R1153 (0x481) - DSP1 RX EQ Gains (2)
+ */
+#define WM8915_DSP1RX_EQ_B4_GAIN_MASK           0xF800  /* DSP1RX_EQ_B4_GAIN - [15:11] */
+#define WM8915_DSP1RX_EQ_B4_GAIN_SHIFT              11  /* DSP1RX_EQ_B4_GAIN - [15:11] */
+#define WM8915_DSP1RX_EQ_B4_GAIN_WIDTH               5  /* DSP1RX_EQ_B4_GAIN - [15:11] */
+#define WM8915_DSP1RX_EQ_B5_GAIN_MASK           0x07C0  /* DSP1RX_EQ_B5_GAIN - [10:6] */
+#define WM8915_DSP1RX_EQ_B5_GAIN_SHIFT               6  /* DSP1RX_EQ_B5_GAIN - [10:6] */
+#define WM8915_DSP1RX_EQ_B5_GAIN_WIDTH               5  /* DSP1RX_EQ_B5_GAIN - [10:6] */
+
+/*
+ * R1154 (0x482) - DSP1 RX EQ Band 1 A
+ */
+#define WM8915_DSP1RX_EQ_B1_A_MASK              0xFFFF  /* DSP1RX_EQ_B1_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B1_A_SHIFT                  0  /* DSP1RX_EQ_B1_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B1_A_WIDTH                 16  /* DSP1RX_EQ_B1_A - [15:0] */
+
+/*
+ * R1155 (0x483) - DSP1 RX EQ Band 1 B
+ */
+#define WM8915_DSP1RX_EQ_B1_B_MASK              0xFFFF  /* DSP1RX_EQ_B1_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B1_B_SHIFT                  0  /* DSP1RX_EQ_B1_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B1_B_WIDTH                 16  /* DSP1RX_EQ_B1_B - [15:0] */
+
+/*
+ * R1156 (0x484) - DSP1 RX EQ Band 1 PG
+ */
+#define WM8915_DSP1RX_EQ_B1_PG_MASK             0xFFFF  /* DSP1RX_EQ_B1_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B1_PG_SHIFT                 0  /* DSP1RX_EQ_B1_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B1_PG_WIDTH                16  /* DSP1RX_EQ_B1_PG - [15:0] */
+
+/*
+ * R1157 (0x485) - DSP1 RX EQ Band 2 A
+ */
+#define WM8915_DSP1RX_EQ_B2_A_MASK              0xFFFF  /* DSP1RX_EQ_B2_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_A_SHIFT                  0  /* DSP1RX_EQ_B2_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_A_WIDTH                 16  /* DSP1RX_EQ_B2_A - [15:0] */
+
+/*
+ * R1158 (0x486) - DSP1 RX EQ Band 2 B
+ */
+#define WM8915_DSP1RX_EQ_B2_B_MASK              0xFFFF  /* DSP1RX_EQ_B2_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_B_SHIFT                  0  /* DSP1RX_EQ_B2_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_B_WIDTH                 16  /* DSP1RX_EQ_B2_B - [15:0] */
+
+/*
+ * R1159 (0x487) - DSP1 RX EQ Band 2 C
+ */
+#define WM8915_DSP1RX_EQ_B2_C_MASK              0xFFFF  /* DSP1RX_EQ_B2_C - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_C_SHIFT                  0  /* DSP1RX_EQ_B2_C - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_C_WIDTH                 16  /* DSP1RX_EQ_B2_C - [15:0] */
+
+/*
+ * R1160 (0x488) - DSP1 RX EQ Band 2 PG
+ */
+#define WM8915_DSP1RX_EQ_B2_PG_MASK             0xFFFF  /* DSP1RX_EQ_B2_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_PG_SHIFT                 0  /* DSP1RX_EQ_B2_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_PG_WIDTH                16  /* DSP1RX_EQ_B2_PG - [15:0] */
+
+/*
+ * R1161 (0x489) - DSP1 RX EQ Band 3 A
+ */
+#define WM8915_DSP1RX_EQ_B3_A_MASK              0xFFFF  /* DSP1RX_EQ_B3_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_A_SHIFT                  0  /* DSP1RX_EQ_B3_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_A_WIDTH                 16  /* DSP1RX_EQ_B3_A - [15:0] */
+
+/*
+ * R1162 (0x48A) - DSP1 RX EQ Band 3 B
+ */
+#define WM8915_DSP1RX_EQ_B3_B_MASK              0xFFFF  /* DSP1RX_EQ_B3_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_B_SHIFT                  0  /* DSP1RX_EQ_B3_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_B_WIDTH                 16  /* DSP1RX_EQ_B3_B - [15:0] */
+
+/*
+ * R1163 (0x48B) - DSP1 RX EQ Band 3 C
+ */
+#define WM8915_DSP1RX_EQ_B3_C_MASK              0xFFFF  /* DSP1RX_EQ_B3_C - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_C_SHIFT                  0  /* DSP1RX_EQ_B3_C - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_C_WIDTH                 16  /* DSP1RX_EQ_B3_C - [15:0] */
+
+/*
+ * R1164 (0x48C) - DSP1 RX EQ Band 3 PG
+ */
+#define WM8915_DSP1RX_EQ_B3_PG_MASK             0xFFFF  /* DSP1RX_EQ_B3_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_PG_SHIFT                 0  /* DSP1RX_EQ_B3_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_PG_WIDTH                16  /* DSP1RX_EQ_B3_PG - [15:0] */
+
+/*
+ * R1165 (0x48D) - DSP1 RX EQ Band 4 A
+ */
+#define WM8915_DSP1RX_EQ_B4_A_MASK              0xFFFF  /* DSP1RX_EQ_B4_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_A_SHIFT                  0  /* DSP1RX_EQ_B4_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_A_WIDTH                 16  /* DSP1RX_EQ_B4_A - [15:0] */
+
+/*
+ * R1166 (0x48E) - DSP1 RX EQ Band 4 B
+ */
+#define WM8915_DSP1RX_EQ_B4_B_MASK              0xFFFF  /* DSP1RX_EQ_B4_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_B_SHIFT                  0  /* DSP1RX_EQ_B4_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_B_WIDTH                 16  /* DSP1RX_EQ_B4_B - [15:0] */
+
+/*
+ * R1167 (0x48F) - DSP1 RX EQ Band 4 C
+ */
+#define WM8915_DSP1RX_EQ_B4_C_MASK              0xFFFF  /* DSP1RX_EQ_B4_C - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_C_SHIFT                  0  /* DSP1RX_EQ_B4_C - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_C_WIDTH                 16  /* DSP1RX_EQ_B4_C - [15:0] */
+
+/*
+ * R1168 (0x490) - DSP1 RX EQ Band 4 PG
+ */
+#define WM8915_DSP1RX_EQ_B4_PG_MASK             0xFFFF  /* DSP1RX_EQ_B4_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_PG_SHIFT                 0  /* DSP1RX_EQ_B4_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_PG_WIDTH                16  /* DSP1RX_EQ_B4_PG - [15:0] */
+
+/*
+ * R1169 (0x491) - DSP1 RX EQ Band 5 A
+ */
+#define WM8915_DSP1RX_EQ_B5_A_MASK              0xFFFF  /* DSP1RX_EQ_B5_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B5_A_SHIFT                  0  /* DSP1RX_EQ_B5_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B5_A_WIDTH                 16  /* DSP1RX_EQ_B5_A - [15:0] */
+
+/*
+ * R1170 (0x492) - DSP1 RX EQ Band 5 B
+ */
+#define WM8915_DSP1RX_EQ_B5_B_MASK              0xFFFF  /* DSP1RX_EQ_B5_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B5_B_SHIFT                  0  /* DSP1RX_EQ_B5_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B5_B_WIDTH                 16  /* DSP1RX_EQ_B5_B - [15:0] */
+
+/*
+ * R1171 (0x493) - DSP1 RX EQ Band 5 PG
+ */
+#define WM8915_DSP1RX_EQ_B5_PG_MASK             0xFFFF  /* DSP1RX_EQ_B5_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B5_PG_SHIFT                 0  /* DSP1RX_EQ_B5_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B5_PG_WIDTH                16  /* DSP1RX_EQ_B5_PG - [15:0] */
+
+/*
+ * R1280 (0x500) - DSP2 TX Left Volume
+ */
+#define WM8915_DSP2TX_VU                        0x0100  /* DSP2TX_VU */
+#define WM8915_DSP2TX_VU_MASK                   0x0100  /* DSP2TX_VU */
+#define WM8915_DSP2TX_VU_SHIFT                       8  /* DSP2TX_VU */
+#define WM8915_DSP2TX_VU_WIDTH                       1  /* DSP2TX_VU */
+#define WM8915_DSP2TXL_VOL_MASK                 0x00FF  /* DSP2TXL_VOL - [7:0] */
+#define WM8915_DSP2TXL_VOL_SHIFT                     0  /* DSP2TXL_VOL - [7:0] */
+#define WM8915_DSP2TXL_VOL_WIDTH                     8  /* DSP2TXL_VOL - [7:0] */
+
+/*
+ * R1281 (0x501) - DSP2 TX Right Volume
+ */
+#define WM8915_DSP2TX_VU                        0x0100  /* DSP2TX_VU */
+#define WM8915_DSP2TX_VU_MASK                   0x0100  /* DSP2TX_VU */
+#define WM8915_DSP2TX_VU_SHIFT                       8  /* DSP2TX_VU */
+#define WM8915_DSP2TX_VU_WIDTH                       1  /* DSP2TX_VU */
+#define WM8915_DSP2TXR_VOL_MASK                 0x00FF  /* DSP2TXR_VOL - [7:0] */
+#define WM8915_DSP2TXR_VOL_SHIFT                     0  /* DSP2TXR_VOL - [7:0] */
+#define WM8915_DSP2TXR_VOL_WIDTH                     8  /* DSP2TXR_VOL - [7:0] */
+
+/*
+ * R1282 (0x502) - DSP2 RX Left Volume
+ */
+#define WM8915_DSP2RX_VU                        0x0100  /* DSP2RX_VU */
+#define WM8915_DSP2RX_VU_MASK                   0x0100  /* DSP2RX_VU */
+#define WM8915_DSP2RX_VU_SHIFT                       8  /* DSP2RX_VU */
+#define WM8915_DSP2RX_VU_WIDTH                       1  /* DSP2RX_VU */
+#define WM8915_DSP2RXL_VOL_MASK                 0x00FF  /* DSP2RXL_VOL - [7:0] */
+#define WM8915_DSP2RXL_VOL_SHIFT                     0  /* DSP2RXL_VOL - [7:0] */
+#define WM8915_DSP2RXL_VOL_WIDTH                     8  /* DSP2RXL_VOL - [7:0] */
+
+/*
+ * R1283 (0x503) - DSP2 RX Right Volume
+ */
+#define WM8915_DSP2RX_VU                        0x0100  /* DSP2RX_VU */
+#define WM8915_DSP2RX_VU_MASK                   0x0100  /* DSP2RX_VU */
+#define WM8915_DSP2RX_VU_SHIFT                       8  /* DSP2RX_VU */
+#define WM8915_DSP2RX_VU_WIDTH                       1  /* DSP2RX_VU */
+#define WM8915_DSP2RXR_VOL_MASK                 0x00FF  /* DSP2RXR_VOL - [7:0] */
+#define WM8915_DSP2RXR_VOL_SHIFT                     0  /* DSP2RXR_VOL - [7:0] */
+#define WM8915_DSP2RXR_VOL_WIDTH                     8  /* DSP2RXR_VOL - [7:0] */
+
+/*
+ * R1296 (0x510) - DSP2 TX Filters
+ */
+#define WM8915_DSP2TX_NF                        0x2000  /* DSP2TX_NF */
+#define WM8915_DSP2TX_NF_MASK                   0x2000  /* DSP2TX_NF */
+#define WM8915_DSP2TX_NF_SHIFT                      13  /* DSP2TX_NF */
+#define WM8915_DSP2TX_NF_WIDTH                       1  /* DSP2TX_NF */
+#define WM8915_DSP2TXL_HPF                      0x1000  /* DSP2TXL_HPF */
+#define WM8915_DSP2TXL_HPF_MASK                 0x1000  /* DSP2TXL_HPF */
+#define WM8915_DSP2TXL_HPF_SHIFT                    12  /* DSP2TXL_HPF */
+#define WM8915_DSP2TXL_HPF_WIDTH                     1  /* DSP2TXL_HPF */
+#define WM8915_DSP2TXR_HPF                      0x0800  /* DSP2TXR_HPF */
+#define WM8915_DSP2TXR_HPF_MASK                 0x0800  /* DSP2TXR_HPF */
+#define WM8915_DSP2TXR_HPF_SHIFT                    11  /* DSP2TXR_HPF */
+#define WM8915_DSP2TXR_HPF_WIDTH                     1  /* DSP2TXR_HPF */
+#define WM8915_DSP2TX_HPF_MODE_MASK             0x0018  /* DSP2TX_HPF_MODE - [4:3] */
+#define WM8915_DSP2TX_HPF_MODE_SHIFT                 3  /* DSP2TX_HPF_MODE - [4:3] */
+#define WM8915_DSP2TX_HPF_MODE_WIDTH                 2  /* DSP2TX_HPF_MODE - [4:3] */
+#define WM8915_DSP2TX_HPF_CUT_MASK              0x0007  /* DSP2TX_HPF_CUT - [2:0] */
+#define WM8915_DSP2TX_HPF_CUT_SHIFT                  0  /* DSP2TX_HPF_CUT - [2:0] */
+#define WM8915_DSP2TX_HPF_CUT_WIDTH                  3  /* DSP2TX_HPF_CUT - [2:0] */
+
+/*
+ * R1312 (0x520) - DSP2 RX Filters (1)
+ */
+#define WM8915_DSP2RX_MUTE                      0x0200  /* DSP2RX_MUTE */
+#define WM8915_DSP2RX_MUTE_MASK                 0x0200  /* DSP2RX_MUTE */
+#define WM8915_DSP2RX_MUTE_SHIFT                     9  /* DSP2RX_MUTE */
+#define WM8915_DSP2RX_MUTE_WIDTH                     1  /* DSP2RX_MUTE */
+#define WM8915_DSP2RX_MONO                      0x0080  /* DSP2RX_MONO */
+#define WM8915_DSP2RX_MONO_MASK                 0x0080  /* DSP2RX_MONO */
+#define WM8915_DSP2RX_MONO_SHIFT                     7  /* DSP2RX_MONO */
+#define WM8915_DSP2RX_MONO_WIDTH                     1  /* DSP2RX_MONO */
+#define WM8915_DSP2RX_MUTERATE                  0x0020  /* DSP2RX_MUTERATE */
+#define WM8915_DSP2RX_MUTERATE_MASK             0x0020  /* DSP2RX_MUTERATE */
+#define WM8915_DSP2RX_MUTERATE_SHIFT                 5  /* DSP2RX_MUTERATE */
+#define WM8915_DSP2RX_MUTERATE_WIDTH                 1  /* DSP2RX_MUTERATE */
+#define WM8915_DSP2RX_UNMUTE_RAMP               0x0010  /* DSP2RX_UNMUTE_RAMP */
+#define WM8915_DSP2RX_UNMUTE_RAMP_MASK          0x0010  /* DSP2RX_UNMUTE_RAMP */
+#define WM8915_DSP2RX_UNMUTE_RAMP_SHIFT              4  /* DSP2RX_UNMUTE_RAMP */
+#define WM8915_DSP2RX_UNMUTE_RAMP_WIDTH              1  /* DSP2RX_UNMUTE_RAMP */
+
+/*
+ * R1313 (0x521) - DSP2 RX Filters (2)
+ */
+#define WM8915_DSP2RX_3D_GAIN_MASK              0x3E00  /* DSP2RX_3D_GAIN - [13:9] */
+#define WM8915_DSP2RX_3D_GAIN_SHIFT                  9  /* DSP2RX_3D_GAIN - [13:9] */
+#define WM8915_DSP2RX_3D_GAIN_WIDTH                  5  /* DSP2RX_3D_GAIN - [13:9] */
+#define WM8915_DSP2RX_3D_ENA                    0x0100  /* DSP2RX_3D_ENA */
+#define WM8915_DSP2RX_3D_ENA_MASK               0x0100  /* DSP2RX_3D_ENA */
+#define WM8915_DSP2RX_3D_ENA_SHIFT                   8  /* DSP2RX_3D_ENA */
+#define WM8915_DSP2RX_3D_ENA_WIDTH                   1  /* DSP2RX_3D_ENA */
+
+/*
+ * R1344 (0x540) - DSP2 DRC (1)
+ */
+#define WM8915_DSP2DRC_SIG_DET_RMS_MASK         0xF800  /* DSP2DRC_SIG_DET_RMS - [15:11] */
+#define WM8915_DSP2DRC_SIG_DET_RMS_SHIFT            11  /* DSP2DRC_SIG_DET_RMS - [15:11] */
+#define WM8915_DSP2DRC_SIG_DET_RMS_WIDTH             5  /* DSP2DRC_SIG_DET_RMS - [15:11] */
+#define WM8915_DSP2DRC_SIG_DET_PK_MASK          0x0600  /* DSP2DRC_SIG_DET_PK - [10:9] */
+#define WM8915_DSP2DRC_SIG_DET_PK_SHIFT              9  /* DSP2DRC_SIG_DET_PK - [10:9] */
+#define WM8915_DSP2DRC_SIG_DET_PK_WIDTH              2  /* DSP2DRC_SIG_DET_PK - [10:9] */
+#define WM8915_DSP2DRC_NG_ENA                   0x0100  /* DSP2DRC_NG_ENA */
+#define WM8915_DSP2DRC_NG_ENA_MASK              0x0100  /* DSP2DRC_NG_ENA */
+#define WM8915_DSP2DRC_NG_ENA_SHIFT                  8  /* DSP2DRC_NG_ENA */
+#define WM8915_DSP2DRC_NG_ENA_WIDTH                  1  /* DSP2DRC_NG_ENA */
+#define WM8915_DSP2DRC_SIG_DET_MODE             0x0080  /* DSP2DRC_SIG_DET_MODE */
+#define WM8915_DSP2DRC_SIG_DET_MODE_MASK        0x0080  /* DSP2DRC_SIG_DET_MODE */
+#define WM8915_DSP2DRC_SIG_DET_MODE_SHIFT            7  /* DSP2DRC_SIG_DET_MODE */
+#define WM8915_DSP2DRC_SIG_DET_MODE_WIDTH            1  /* DSP2DRC_SIG_DET_MODE */
+#define WM8915_DSP2DRC_SIG_DET                  0x0040  /* DSP2DRC_SIG_DET */
+#define WM8915_DSP2DRC_SIG_DET_MASK             0x0040  /* DSP2DRC_SIG_DET */
+#define WM8915_DSP2DRC_SIG_DET_SHIFT                 6  /* DSP2DRC_SIG_DET */
+#define WM8915_DSP2DRC_SIG_DET_WIDTH                 1  /* DSP2DRC_SIG_DET */
+#define WM8915_DSP2DRC_KNEE2_OP_ENA             0x0020  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8915_DSP2DRC_KNEE2_OP_ENA_MASK        0x0020  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8915_DSP2DRC_KNEE2_OP_ENA_SHIFT            5  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8915_DSP2DRC_KNEE2_OP_ENA_WIDTH            1  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8915_DSP2DRC_QR                       0x0010  /* DSP2DRC_QR */
+#define WM8915_DSP2DRC_QR_MASK                  0x0010  /* DSP2DRC_QR */
+#define WM8915_DSP2DRC_QR_SHIFT                      4  /* DSP2DRC_QR */
+#define WM8915_DSP2DRC_QR_WIDTH                      1  /* DSP2DRC_QR */
+#define WM8915_DSP2DRC_ANTICLIP                 0x0008  /* DSP2DRC_ANTICLIP */
+#define WM8915_DSP2DRC_ANTICLIP_MASK            0x0008  /* DSP2DRC_ANTICLIP */
+#define WM8915_DSP2DRC_ANTICLIP_SHIFT                3  /* DSP2DRC_ANTICLIP */
+#define WM8915_DSP2DRC_ANTICLIP_WIDTH                1  /* DSP2DRC_ANTICLIP */
+#define WM8915_DSP2RX_DRC_ENA                   0x0004  /* DSP2RX_DRC_ENA */
+#define WM8915_DSP2RX_DRC_ENA_MASK              0x0004  /* DSP2RX_DRC_ENA */
+#define WM8915_DSP2RX_DRC_ENA_SHIFT                  2  /* DSP2RX_DRC_ENA */
+#define WM8915_DSP2RX_DRC_ENA_WIDTH                  1  /* DSP2RX_DRC_ENA */
+#define WM8915_DSP2TXL_DRC_ENA                  0x0002  /* DSP2TXL_DRC_ENA */
+#define WM8915_DSP2TXL_DRC_ENA_MASK             0x0002  /* DSP2TXL_DRC_ENA */
+#define WM8915_DSP2TXL_DRC_ENA_SHIFT                 1  /* DSP2TXL_DRC_ENA */
+#define WM8915_DSP2TXL_DRC_ENA_WIDTH                 1  /* DSP2TXL_DRC_ENA */
+#define WM8915_DSP2TXR_DRC_ENA                  0x0001  /* DSP2TXR_DRC_ENA */
+#define WM8915_DSP2TXR_DRC_ENA_MASK             0x0001  /* DSP2TXR_DRC_ENA */
+#define WM8915_DSP2TXR_DRC_ENA_SHIFT                 0  /* DSP2TXR_DRC_ENA */
+#define WM8915_DSP2TXR_DRC_ENA_WIDTH                 1  /* DSP2TXR_DRC_ENA */
+
+/*
+ * R1345 (0x541) - DSP2 DRC (2)
+ */
+#define WM8915_DSP2DRC_ATK_MASK                 0x1E00  /* DSP2DRC_ATK - [12:9] */
+#define WM8915_DSP2DRC_ATK_SHIFT                     9  /* DSP2DRC_ATK - [12:9] */
+#define WM8915_DSP2DRC_ATK_WIDTH                     4  /* DSP2DRC_ATK - [12:9] */
+#define WM8915_DSP2DRC_DCY_MASK                 0x01E0  /* DSP2DRC_DCY - [8:5] */
+#define WM8915_DSP2DRC_DCY_SHIFT                     5  /* DSP2DRC_DCY - [8:5] */
+#define WM8915_DSP2DRC_DCY_WIDTH                     4  /* DSP2DRC_DCY - [8:5] */
+#define WM8915_DSP2DRC_MINGAIN_MASK             0x001C  /* DSP2DRC_MINGAIN - [4:2] */
+#define WM8915_DSP2DRC_MINGAIN_SHIFT                 2  /* DSP2DRC_MINGAIN - [4:2] */
+#define WM8915_DSP2DRC_MINGAIN_WIDTH                 3  /* DSP2DRC_MINGAIN - [4:2] */
+#define WM8915_DSP2DRC_MAXGAIN_MASK             0x0003  /* DSP2DRC_MAXGAIN - [1:0] */
+#define WM8915_DSP2DRC_MAXGAIN_SHIFT                 0  /* DSP2DRC_MAXGAIN - [1:0] */
+#define WM8915_DSP2DRC_MAXGAIN_WIDTH                 2  /* DSP2DRC_MAXGAIN - [1:0] */
+
+/*
+ * R1346 (0x542) - DSP2 DRC (3)
+ */
+#define WM8915_DSP2DRC_NG_MINGAIN_MASK          0xF000  /* DSP2DRC_NG_MINGAIN - [15:12] */
+#define WM8915_DSP2DRC_NG_MINGAIN_SHIFT             12  /* DSP2DRC_NG_MINGAIN - [15:12] */
+#define WM8915_DSP2DRC_NG_MINGAIN_WIDTH              4  /* DSP2DRC_NG_MINGAIN - [15:12] */
+#define WM8915_DSP2DRC_NG_EXP_MASK              0x0C00  /* DSP2DRC_NG_EXP - [11:10] */
+#define WM8915_DSP2DRC_NG_EXP_SHIFT                 10  /* DSP2DRC_NG_EXP - [11:10] */
+#define WM8915_DSP2DRC_NG_EXP_WIDTH                  2  /* DSP2DRC_NG_EXP - [11:10] */
+#define WM8915_DSP2DRC_QR_THR_MASK              0x0300  /* DSP2DRC_QR_THR - [9:8] */
+#define WM8915_DSP2DRC_QR_THR_SHIFT                  8  /* DSP2DRC_QR_THR - [9:8] */
+#define WM8915_DSP2DRC_QR_THR_WIDTH                  2  /* DSP2DRC_QR_THR - [9:8] */
+#define WM8915_DSP2DRC_QR_DCY_MASK              0x00C0  /* DSP2DRC_QR_DCY - [7:6] */
+#define WM8915_DSP2DRC_QR_DCY_SHIFT                  6  /* DSP2DRC_QR_DCY - [7:6] */
+#define WM8915_DSP2DRC_QR_DCY_WIDTH                  2  /* DSP2DRC_QR_DCY - [7:6] */
+#define WM8915_DSP2DRC_HI_COMP_MASK             0x0038  /* DSP2DRC_HI_COMP - [5:3] */
+#define WM8915_DSP2DRC_HI_COMP_SHIFT                 3  /* DSP2DRC_HI_COMP - [5:3] */
+#define WM8915_DSP2DRC_HI_COMP_WIDTH                 3  /* DSP2DRC_HI_COMP - [5:3] */
+#define WM8915_DSP2DRC_LO_COMP_MASK             0x0007  /* DSP2DRC_LO_COMP - [2:0] */
+#define WM8915_DSP2DRC_LO_COMP_SHIFT                 0  /* DSP2DRC_LO_COMP - [2:0] */
+#define WM8915_DSP2DRC_LO_COMP_WIDTH                 3  /* DSP2DRC_LO_COMP - [2:0] */
+
+/*
+ * R1347 (0x543) - DSP2 DRC (4)
+ */
+#define WM8915_DSP2DRC_KNEE_IP_MASK             0x07E0  /* DSP2DRC_KNEE_IP - [10:5] */
+#define WM8915_DSP2DRC_KNEE_IP_SHIFT                 5  /* DSP2DRC_KNEE_IP - [10:5] */
+#define WM8915_DSP2DRC_KNEE_IP_WIDTH                 6  /* DSP2DRC_KNEE_IP - [10:5] */
+#define WM8915_DSP2DRC_KNEE_OP_MASK             0x001F  /* DSP2DRC_KNEE_OP - [4:0] */
+#define WM8915_DSP2DRC_KNEE_OP_SHIFT                 0  /* DSP2DRC_KNEE_OP - [4:0] */
+#define WM8915_DSP2DRC_KNEE_OP_WIDTH                 5  /* DSP2DRC_KNEE_OP - [4:0] */
+
+/*
+ * R1348 (0x544) - DSP2 DRC (5)
+ */
+#define WM8915_DSP2DRC_KNEE2_IP_MASK            0x03E0  /* DSP2DRC_KNEE2_IP - [9:5] */
+#define WM8915_DSP2DRC_KNEE2_IP_SHIFT                5  /* DSP2DRC_KNEE2_IP - [9:5] */
+#define WM8915_DSP2DRC_KNEE2_IP_WIDTH                5  /* DSP2DRC_KNEE2_IP - [9:5] */
+#define WM8915_DSP2DRC_KNEE2_OP_MASK            0x001F  /* DSP2DRC_KNEE2_OP - [4:0] */
+#define WM8915_DSP2DRC_KNEE2_OP_SHIFT                0  /* DSP2DRC_KNEE2_OP - [4:0] */
+#define WM8915_DSP2DRC_KNEE2_OP_WIDTH                5  /* DSP2DRC_KNEE2_OP - [4:0] */
+
+/*
+ * R1408 (0x580) - DSP2 RX EQ Gains (1)
+ */
+#define WM8915_DSP2RX_EQ_B1_GAIN_MASK           0xF800  /* DSP2RX_EQ_B1_GAIN - [15:11] */
+#define WM8915_DSP2RX_EQ_B1_GAIN_SHIFT              11  /* DSP2RX_EQ_B1_GAIN - [15:11] */
+#define WM8915_DSP2RX_EQ_B1_GAIN_WIDTH               5  /* DSP2RX_EQ_B1_GAIN - [15:11] */
+#define WM8915_DSP2RX_EQ_B2_GAIN_MASK           0x07C0  /* DSP2RX_EQ_B2_GAIN - [10:6] */
+#define WM8915_DSP2RX_EQ_B2_GAIN_SHIFT               6  /* DSP2RX_EQ_B2_GAIN - [10:6] */
+#define WM8915_DSP2RX_EQ_B2_GAIN_WIDTH               5  /* DSP2RX_EQ_B2_GAIN - [10:6] */
+#define WM8915_DSP2RX_EQ_B3_GAIN_MASK           0x003E  /* DSP2RX_EQ_B3_GAIN - [5:1] */
+#define WM8915_DSP2RX_EQ_B3_GAIN_SHIFT               1  /* DSP2RX_EQ_B3_GAIN - [5:1] */
+#define WM8915_DSP2RX_EQ_B3_GAIN_WIDTH               5  /* DSP2RX_EQ_B3_GAIN - [5:1] */
+#define WM8915_DSP2RX_EQ_ENA                    0x0001  /* DSP2RX_EQ_ENA */
+#define WM8915_DSP2RX_EQ_ENA_MASK               0x0001  /* DSP2RX_EQ_ENA */
+#define WM8915_DSP2RX_EQ_ENA_SHIFT                   0  /* DSP2RX_EQ_ENA */
+#define WM8915_DSP2RX_EQ_ENA_WIDTH                   1  /* DSP2RX_EQ_ENA */
+
+/*
+ * R1409 (0x581) - DSP2 RX EQ Gains (2)
+ */
+#define WM8915_DSP2RX_EQ_B4_GAIN_MASK           0xF800  /* DSP2RX_EQ_B4_GAIN - [15:11] */
+#define WM8915_DSP2RX_EQ_B4_GAIN_SHIFT              11  /* DSP2RX_EQ_B4_GAIN - [15:11] */
+#define WM8915_DSP2RX_EQ_B4_GAIN_WIDTH               5  /* DSP2RX_EQ_B4_GAIN - [15:11] */
+#define WM8915_DSP2RX_EQ_B5_GAIN_MASK           0x07C0  /* DSP2RX_EQ_B5_GAIN - [10:6] */
+#define WM8915_DSP2RX_EQ_B5_GAIN_SHIFT               6  /* DSP2RX_EQ_B5_GAIN - [10:6] */
+#define WM8915_DSP2RX_EQ_B5_GAIN_WIDTH               5  /* DSP2RX_EQ_B5_GAIN - [10:6] */
+
+/*
+ * R1410 (0x582) - DSP2 RX EQ Band 1 A
+ */
+#define WM8915_DSP2RX_EQ_B1_A_MASK              0xFFFF  /* DSP2RX_EQ_B1_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B1_A_SHIFT                  0  /* DSP2RX_EQ_B1_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B1_A_WIDTH                 16  /* DSP2RX_EQ_B1_A - [15:0] */
+
+/*
+ * R1411 (0x583) - DSP2 RX EQ Band 1 B
+ */
+#define WM8915_DSP2RX_EQ_B1_B_MASK              0xFFFF  /* DSP2RX_EQ_B1_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B1_B_SHIFT                  0  /* DSP2RX_EQ_B1_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B1_B_WIDTH                 16  /* DSP2RX_EQ_B1_B - [15:0] */
+
+/*
+ * R1412 (0x584) - DSP2 RX EQ Band 1 PG
+ */
+#define WM8915_DSP2RX_EQ_B1_PG_MASK             0xFFFF  /* DSP2RX_EQ_B1_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B1_PG_SHIFT                 0  /* DSP2RX_EQ_B1_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B1_PG_WIDTH                16  /* DSP2RX_EQ_B1_PG - [15:0] */
+
+/*
+ * R1413 (0x585) - DSP2 RX EQ Band 2 A
+ */
+#define WM8915_DSP2RX_EQ_B2_A_MASK              0xFFFF  /* DSP2RX_EQ_B2_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_A_SHIFT                  0  /* DSP2RX_EQ_B2_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_A_WIDTH                 16  /* DSP2RX_EQ_B2_A - [15:0] */
+
+/*
+ * R1414 (0x586) - DSP2 RX EQ Band 2 B
+ */
+#define WM8915_DSP2RX_EQ_B2_B_MASK              0xFFFF  /* DSP2RX_EQ_B2_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_B_SHIFT                  0  /* DSP2RX_EQ_B2_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_B_WIDTH                 16  /* DSP2RX_EQ_B2_B - [15:0] */
+
+/*
+ * R1415 (0x587) - DSP2 RX EQ Band 2 C
+ */
+#define WM8915_DSP2RX_EQ_B2_C_MASK              0xFFFF  /* DSP2RX_EQ_B2_C - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_C_SHIFT                  0  /* DSP2RX_EQ_B2_C - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_C_WIDTH                 16  /* DSP2RX_EQ_B2_C - [15:0] */
+
+/*
+ * R1416 (0x588) - DSP2 RX EQ Band 2 PG
+ */
+#define WM8915_DSP2RX_EQ_B2_PG_MASK             0xFFFF  /* DSP2RX_EQ_B2_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_PG_SHIFT                 0  /* DSP2RX_EQ_B2_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_PG_WIDTH                16  /* DSP2RX_EQ_B2_PG - [15:0] */
+
+/*
+ * R1417 (0x589) - DSP2 RX EQ Band 3 A
+ */
+#define WM8915_DSP2RX_EQ_B3_A_MASK              0xFFFF  /* DSP2RX_EQ_B3_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_A_SHIFT                  0  /* DSP2RX_EQ_B3_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_A_WIDTH                 16  /* DSP2RX_EQ_B3_A - [15:0] */
+
+/*
+ * R1418 (0x58A) - DSP2 RX EQ Band 3 B
+ */
+#define WM8915_DSP2RX_EQ_B3_B_MASK              0xFFFF  /* DSP2RX_EQ_B3_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_B_SHIFT                  0  /* DSP2RX_EQ_B3_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_B_WIDTH                 16  /* DSP2RX_EQ_B3_B - [15:0] */
+
+/*
+ * R1419 (0x58B) - DSP2 RX EQ Band 3 C
+ */
+#define WM8915_DSP2RX_EQ_B3_C_MASK              0xFFFF  /* DSP2RX_EQ_B3_C - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_C_SHIFT                  0  /* DSP2RX_EQ_B3_C - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_C_WIDTH                 16  /* DSP2RX_EQ_B3_C - [15:0] */
+
+/*
+ * R1420 (0x58C) - DSP2 RX EQ Band 3 PG
+ */
+#define WM8915_DSP2RX_EQ_B3_PG_MASK             0xFFFF  /* DSP2RX_EQ_B3_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_PG_SHIFT                 0  /* DSP2RX_EQ_B3_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_PG_WIDTH                16  /* DSP2RX_EQ_B3_PG - [15:0] */
+
+/*
+ * R1421 (0x58D) - DSP2 RX EQ Band 4 A
+ */
+#define WM8915_DSP2RX_EQ_B4_A_MASK              0xFFFF  /* DSP2RX_EQ_B4_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_A_SHIFT                  0  /* DSP2RX_EQ_B4_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_A_WIDTH                 16  /* DSP2RX_EQ_B4_A - [15:0] */
+
+/*
+ * R1422 (0x58E) - DSP2 RX EQ Band 4 B
+ */
+#define WM8915_DSP2RX_EQ_B4_B_MASK              0xFFFF  /* DSP2RX_EQ_B4_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_B_SHIFT                  0  /* DSP2RX_EQ_B4_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_B_WIDTH                 16  /* DSP2RX_EQ_B4_B - [15:0] */
+
+/*
+ * R1423 (0x58F) - DSP2 RX EQ Band 4 C
+ */
+#define WM8915_DSP2RX_EQ_B4_C_MASK              0xFFFF  /* DSP2RX_EQ_B4_C - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_C_SHIFT                  0  /* DSP2RX_EQ_B4_C - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_C_WIDTH                 16  /* DSP2RX_EQ_B4_C - [15:0] */
+
+/*
+ * R1424 (0x590) - DSP2 RX EQ Band 4 PG
+ */
+#define WM8915_DSP2RX_EQ_B4_PG_MASK             0xFFFF  /* DSP2RX_EQ_B4_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_PG_SHIFT                 0  /* DSP2RX_EQ_B4_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_PG_WIDTH                16  /* DSP2RX_EQ_B4_PG - [15:0] */
+
+/*
+ * R1425 (0x591) - DSP2 RX EQ Band 5 A
+ */
+#define WM8915_DSP2RX_EQ_B5_A_MASK              0xFFFF  /* DSP2RX_EQ_B5_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B5_A_SHIFT                  0  /* DSP2RX_EQ_B5_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B5_A_WIDTH                 16  /* DSP2RX_EQ_B5_A - [15:0] */
+
+/*
+ * R1426 (0x592) - DSP2 RX EQ Band 5 B
+ */
+#define WM8915_DSP2RX_EQ_B5_B_MASK              0xFFFF  /* DSP2RX_EQ_B5_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B5_B_SHIFT                  0  /* DSP2RX_EQ_B5_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B5_B_WIDTH                 16  /* DSP2RX_EQ_B5_B - [15:0] */
+
+/*
+ * R1427 (0x593) - DSP2 RX EQ Band 5 PG
+ */
+#define WM8915_DSP2RX_EQ_B5_PG_MASK             0xFFFF  /* DSP2RX_EQ_B5_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B5_PG_SHIFT                 0  /* DSP2RX_EQ_B5_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B5_PG_WIDTH                16  /* DSP2RX_EQ_B5_PG - [15:0] */
+
+/*
+ * R1536 (0x600) - DAC1 Mixer Volumes
+ */
+#define WM8915_ADCR_DAC1_VOL_MASK               0x03E0  /* ADCR_DAC1_VOL - [9:5] */
+#define WM8915_ADCR_DAC1_VOL_SHIFT                   5  /* ADCR_DAC1_VOL - [9:5] */
+#define WM8915_ADCR_DAC1_VOL_WIDTH                   5  /* ADCR_DAC1_VOL - [9:5] */
+#define WM8915_ADCL_DAC1_VOL_MASK               0x001F  /* ADCL_DAC1_VOL - [4:0] */
+#define WM8915_ADCL_DAC1_VOL_SHIFT                   0  /* ADCL_DAC1_VOL - [4:0] */
+#define WM8915_ADCL_DAC1_VOL_WIDTH                   5  /* ADCL_DAC1_VOL - [4:0] */
+
+/*
+ * R1537 (0x601) - DAC1 Left Mixer Routing
+ */
+#define WM8915_ADCR_TO_DAC1L                    0x0020  /* ADCR_TO_DAC1L */
+#define WM8915_ADCR_TO_DAC1L_MASK               0x0020  /* ADCR_TO_DAC1L */
+#define WM8915_ADCR_TO_DAC1L_SHIFT                   5  /* ADCR_TO_DAC1L */
+#define WM8915_ADCR_TO_DAC1L_WIDTH                   1  /* ADCR_TO_DAC1L */
+#define WM8915_ADCL_TO_DAC1L                    0x0010  /* ADCL_TO_DAC1L */
+#define WM8915_ADCL_TO_DAC1L_MASK               0x0010  /* ADCL_TO_DAC1L */
+#define WM8915_ADCL_TO_DAC1L_SHIFT                   4  /* ADCL_TO_DAC1L */
+#define WM8915_ADCL_TO_DAC1L_WIDTH                   1  /* ADCL_TO_DAC1L */
+#define WM8915_DSP2RXL_TO_DAC1L                 0x0002  /* DSP2RXL_TO_DAC1L */
+#define WM8915_DSP2RXL_TO_DAC1L_MASK            0x0002  /* DSP2RXL_TO_DAC1L */
+#define WM8915_DSP2RXL_TO_DAC1L_SHIFT                1  /* DSP2RXL_TO_DAC1L */
+#define WM8915_DSP2RXL_TO_DAC1L_WIDTH                1  /* DSP2RXL_TO_DAC1L */
+#define WM8915_DSP1RXL_TO_DAC1L                 0x0001  /* DSP1RXL_TO_DAC1L */
+#define WM8915_DSP1RXL_TO_DAC1L_MASK            0x0001  /* DSP1RXL_TO_DAC1L */
+#define WM8915_DSP1RXL_TO_DAC1L_SHIFT                0  /* DSP1RXL_TO_DAC1L */
+#define WM8915_DSP1RXL_TO_DAC1L_WIDTH                1  /* DSP1RXL_TO_DAC1L */
+
+/*
+ * R1538 (0x602) - DAC1 Right Mixer Routing
+ */
+#define WM8915_ADCR_TO_DAC1R                    0x0020  /* ADCR_TO_DAC1R */
+#define WM8915_ADCR_TO_DAC1R_MASK               0x0020  /* ADCR_TO_DAC1R */
+#define WM8915_ADCR_TO_DAC1R_SHIFT                   5  /* ADCR_TO_DAC1R */
+#define WM8915_ADCR_TO_DAC1R_WIDTH                   1  /* ADCR_TO_DAC1R */
+#define WM8915_ADCL_TO_DAC1R                    0x0010  /* ADCL_TO_DAC1R */
+#define WM8915_ADCL_TO_DAC1R_MASK               0x0010  /* ADCL_TO_DAC1R */
+#define WM8915_ADCL_TO_DAC1R_SHIFT                   4  /* ADCL_TO_DAC1R */
+#define WM8915_ADCL_TO_DAC1R_WIDTH                   1  /* ADCL_TO_DAC1R */
+#define WM8915_DSP2RXR_TO_DAC1R                 0x0002  /* DSP2RXR_TO_DAC1R */
+#define WM8915_DSP2RXR_TO_DAC1R_MASK            0x0002  /* DSP2RXR_TO_DAC1R */
+#define WM8915_DSP2RXR_TO_DAC1R_SHIFT                1  /* DSP2RXR_TO_DAC1R */
+#define WM8915_DSP2RXR_TO_DAC1R_WIDTH                1  /* DSP2RXR_TO_DAC1R */
+#define WM8915_DSP1RXR_TO_DAC1R                 0x0001  /* DSP1RXR_TO_DAC1R */
+#define WM8915_DSP1RXR_TO_DAC1R_MASK            0x0001  /* DSP1RXR_TO_DAC1R */
+#define WM8915_DSP1RXR_TO_DAC1R_SHIFT                0  /* DSP1RXR_TO_DAC1R */
+#define WM8915_DSP1RXR_TO_DAC1R_WIDTH                1  /* DSP1RXR_TO_DAC1R */
+
+/*
+ * R1539 (0x603) - DAC2 Mixer Volumes
+ */
+#define WM8915_ADCR_DAC2_VOL_MASK               0x03E0  /* ADCR_DAC2_VOL - [9:5] */
+#define WM8915_ADCR_DAC2_VOL_SHIFT                   5  /* ADCR_DAC2_VOL - [9:5] */
+#define WM8915_ADCR_DAC2_VOL_WIDTH                   5  /* ADCR_DAC2_VOL - [9:5] */
+#define WM8915_ADCL_DAC2_VOL_MASK               0x001F  /* ADCL_DAC2_VOL - [4:0] */
+#define WM8915_ADCL_DAC2_VOL_SHIFT                   0  /* ADCL_DAC2_VOL - [4:0] */
+#define WM8915_ADCL_DAC2_VOL_WIDTH                   5  /* ADCL_DAC2_VOL - [4:0] */
+
+/*
+ * R1540 (0x604) - DAC2 Left Mixer Routing
+ */
+#define WM8915_ADCR_TO_DAC2L                    0x0020  /* ADCR_TO_DAC2L */
+#define WM8915_ADCR_TO_DAC2L_MASK               0x0020  /* ADCR_TO_DAC2L */
+#define WM8915_ADCR_TO_DAC2L_SHIFT                   5  /* ADCR_TO_DAC2L */
+#define WM8915_ADCR_TO_DAC2L_WIDTH                   1  /* ADCR_TO_DAC2L */
+#define WM8915_ADCL_TO_DAC2L                    0x0010  /* ADCL_TO_DAC2L */
+#define WM8915_ADCL_TO_DAC2L_MASK               0x0010  /* ADCL_TO_DAC2L */
+#define WM8915_ADCL_TO_DAC2L_SHIFT                   4  /* ADCL_TO_DAC2L */
+#define WM8915_ADCL_TO_DAC2L_WIDTH                   1  /* ADCL_TO_DAC2L */
+#define WM8915_DSP2RXL_TO_DAC2L                 0x0002  /* DSP2RXL_TO_DAC2L */
+#define WM8915_DSP2RXL_TO_DAC2L_MASK            0x0002  /* DSP2RXL_TO_DAC2L */
+#define WM8915_DSP2RXL_TO_DAC2L_SHIFT                1  /* DSP2RXL_TO_DAC2L */
+#define WM8915_DSP2RXL_TO_DAC2L_WIDTH                1  /* DSP2RXL_TO_DAC2L */
+#define WM8915_DSP1RXL_TO_DAC2L                 0x0001  /* DSP1RXL_TO_DAC2L */
+#define WM8915_DSP1RXL_TO_DAC2L_MASK            0x0001  /* DSP1RXL_TO_DAC2L */
+#define WM8915_DSP1RXL_TO_DAC2L_SHIFT                0  /* DSP1RXL_TO_DAC2L */
+#define WM8915_DSP1RXL_TO_DAC2L_WIDTH                1  /* DSP1RXL_TO_DAC2L */
+
+/*
+ * R1541 (0x605) - DAC2 Right Mixer Routing
+ */
+#define WM8915_ADCR_TO_DAC2R                    0x0020  /* ADCR_TO_DAC2R */
+#define WM8915_ADCR_TO_DAC2R_MASK               0x0020  /* ADCR_TO_DAC2R */
+#define WM8915_ADCR_TO_DAC2R_SHIFT                   5  /* ADCR_TO_DAC2R */
+#define WM8915_ADCR_TO_DAC2R_WIDTH                   1  /* ADCR_TO_DAC2R */
+#define WM8915_ADCL_TO_DAC2R                    0x0010  /* ADCL_TO_DAC2R */
+#define WM8915_ADCL_TO_DAC2R_MASK               0x0010  /* ADCL_TO_DAC2R */
+#define WM8915_ADCL_TO_DAC2R_SHIFT                   4  /* ADCL_TO_DAC2R */
+#define WM8915_ADCL_TO_DAC2R_WIDTH                   1  /* ADCL_TO_DAC2R */
+#define WM8915_DSP2RXR_TO_DAC2R                 0x0002  /* DSP2RXR_TO_DAC2R */
+#define WM8915_DSP2RXR_TO_DAC2R_MASK            0x0002  /* DSP2RXR_TO_DAC2R */
+#define WM8915_DSP2RXR_TO_DAC2R_SHIFT                1  /* DSP2RXR_TO_DAC2R */
+#define WM8915_DSP2RXR_TO_DAC2R_WIDTH                1  /* DSP2RXR_TO_DAC2R */
+#define WM8915_DSP1RXR_TO_DAC2R                 0x0001  /* DSP1RXR_TO_DAC2R */
+#define WM8915_DSP1RXR_TO_DAC2R_MASK            0x0001  /* DSP1RXR_TO_DAC2R */
+#define WM8915_DSP1RXR_TO_DAC2R_SHIFT                0  /* DSP1RXR_TO_DAC2R */
+#define WM8915_DSP1RXR_TO_DAC2R_WIDTH                1  /* DSP1RXR_TO_DAC2R */
+
+/*
+ * R1542 (0x606) - DSP1 TX Left Mixer Routing
+ */
+#define WM8915_ADC1L_TO_DSP1TXL                 0x0002  /* ADC1L_TO_DSP1TXL */
+#define WM8915_ADC1L_TO_DSP1TXL_MASK            0x0002  /* ADC1L_TO_DSP1TXL */
+#define WM8915_ADC1L_TO_DSP1TXL_SHIFT                1  /* ADC1L_TO_DSP1TXL */
+#define WM8915_ADC1L_TO_DSP1TXL_WIDTH                1  /* ADC1L_TO_DSP1TXL */
+#define WM8915_DACL_TO_DSP1TXL                  0x0001  /* DACL_TO_DSP1TXL */
+#define WM8915_DACL_TO_DSP1TXL_MASK             0x0001  /* DACL_TO_DSP1TXL */
+#define WM8915_DACL_TO_DSP1TXL_SHIFT                 0  /* DACL_TO_DSP1TXL */
+#define WM8915_DACL_TO_DSP1TXL_WIDTH                 1  /* DACL_TO_DSP1TXL */
+
+/*
+ * R1543 (0x607) - DSP1 TX Right Mixer Routing
+ */
+#define WM8915_ADC1R_TO_DSP1TXR                 0x0002  /* ADC1R_TO_DSP1TXR */
+#define WM8915_ADC1R_TO_DSP1TXR_MASK            0x0002  /* ADC1R_TO_DSP1TXR */
+#define WM8915_ADC1R_TO_DSP1TXR_SHIFT                1  /* ADC1R_TO_DSP1TXR */
+#define WM8915_ADC1R_TO_DSP1TXR_WIDTH                1  /* ADC1R_TO_DSP1TXR */
+#define WM8915_DACR_TO_DSP1TXR                  0x0001  /* DACR_TO_DSP1TXR */
+#define WM8915_DACR_TO_DSP1TXR_MASK             0x0001  /* DACR_TO_DSP1TXR */
+#define WM8915_DACR_TO_DSP1TXR_SHIFT                 0  /* DACR_TO_DSP1TXR */
+#define WM8915_DACR_TO_DSP1TXR_WIDTH                 1  /* DACR_TO_DSP1TXR */
+
+/*
+ * R1544 (0x608) - DSP2 TX Left Mixer Routing
+ */
+#define WM8915_ADC2L_TO_DSP2TXL                 0x0002  /* ADC2L_TO_DSP2TXL */
+#define WM8915_ADC2L_TO_DSP2TXL_MASK            0x0002  /* ADC2L_TO_DSP2TXL */
+#define WM8915_ADC2L_TO_DSP2TXL_SHIFT                1  /* ADC2L_TO_DSP2TXL */
+#define WM8915_ADC2L_TO_DSP2TXL_WIDTH                1  /* ADC2L_TO_DSP2TXL */
+#define WM8915_DACL_TO_DSP2TXL                  0x0001  /* DACL_TO_DSP2TXL */
+#define WM8915_DACL_TO_DSP2TXL_MASK             0x0001  /* DACL_TO_DSP2TXL */
+#define WM8915_DACL_TO_DSP2TXL_SHIFT                 0  /* DACL_TO_DSP2TXL */
+#define WM8915_DACL_TO_DSP2TXL_WIDTH                 1  /* DACL_TO_DSP2TXL */
+
+/*
+ * R1545 (0x609) - DSP2 TX Right Mixer Routing
+ */
+#define WM8915_ADC2R_TO_DSP2TXR                 0x0002  /* ADC2R_TO_DSP2TXR */
+#define WM8915_ADC2R_TO_DSP2TXR_MASK            0x0002  /* ADC2R_TO_DSP2TXR */
+#define WM8915_ADC2R_TO_DSP2TXR_SHIFT                1  /* ADC2R_TO_DSP2TXR */
+#define WM8915_ADC2R_TO_DSP2TXR_WIDTH                1  /* ADC2R_TO_DSP2TXR */
+#define WM8915_DACR_TO_DSP2TXR                  0x0001  /* DACR_TO_DSP2TXR */
+#define WM8915_DACR_TO_DSP2TXR_MASK             0x0001  /* DACR_TO_DSP2TXR */
+#define WM8915_DACR_TO_DSP2TXR_SHIFT                 0  /* DACR_TO_DSP2TXR */
+#define WM8915_DACR_TO_DSP2TXR_WIDTH                 1  /* DACR_TO_DSP2TXR */
+
+/*
+ * R1546 (0x60A) - DSP TX Mixer Select
+ */
+#define WM8915_DAC_TO_DSPTX_SRC                 0x0001  /* DAC_TO_DSPTX_SRC */
+#define WM8915_DAC_TO_DSPTX_SRC_MASK            0x0001  /* DAC_TO_DSPTX_SRC */
+#define WM8915_DAC_TO_DSPTX_SRC_SHIFT                0  /* DAC_TO_DSPTX_SRC */
+#define WM8915_DAC_TO_DSPTX_SRC_WIDTH                1  /* DAC_TO_DSPTX_SRC */
+
+/*
+ * R1552 (0x610) - DAC Softmute
+ */
+#define WM8915_DAC_SOFTMUTEMODE                 0x0002  /* DAC_SOFTMUTEMODE */
+#define WM8915_DAC_SOFTMUTEMODE_MASK            0x0002  /* DAC_SOFTMUTEMODE */
+#define WM8915_DAC_SOFTMUTEMODE_SHIFT                1  /* DAC_SOFTMUTEMODE */
+#define WM8915_DAC_SOFTMUTEMODE_WIDTH                1  /* DAC_SOFTMUTEMODE */
+#define WM8915_DAC_MUTERATE                     0x0001  /* DAC_MUTERATE */
+#define WM8915_DAC_MUTERATE_MASK                0x0001  /* DAC_MUTERATE */
+#define WM8915_DAC_MUTERATE_SHIFT                    0  /* DAC_MUTERATE */
+#define WM8915_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
+
+/*
+ * R1568 (0x620) - Oversampling
+ */
+#define WM8915_SPK_OSR128                       0x0008  /* SPK_OSR128 */
+#define WM8915_SPK_OSR128_MASK                  0x0008  /* SPK_OSR128 */
+#define WM8915_SPK_OSR128_SHIFT                      3  /* SPK_OSR128 */
+#define WM8915_SPK_OSR128_WIDTH                      1  /* SPK_OSR128 */
+#define WM8915_DMIC_OSR64                       0x0004  /* DMIC_OSR64 */
+#define WM8915_DMIC_OSR64_MASK                  0x0004  /* DMIC_OSR64 */
+#define WM8915_DMIC_OSR64_SHIFT                      2  /* DMIC_OSR64 */
+#define WM8915_DMIC_OSR64_WIDTH                      1  /* DMIC_OSR64 */
+#define WM8915_ADC_OSR128                       0x0002  /* ADC_OSR128 */
+#define WM8915_ADC_OSR128_MASK                  0x0002  /* ADC_OSR128 */
+#define WM8915_ADC_OSR128_SHIFT                      1  /* ADC_OSR128 */
+#define WM8915_ADC_OSR128_WIDTH                      1  /* ADC_OSR128 */
+#define WM8915_DAC_OSR128                       0x0001  /* DAC_OSR128 */
+#define WM8915_DAC_OSR128_MASK                  0x0001  /* DAC_OSR128 */
+#define WM8915_DAC_OSR128_SHIFT                      0  /* DAC_OSR128 */
+#define WM8915_DAC_OSR128_WIDTH                      1  /* DAC_OSR128 */
+
+/*
+ * R1569 (0x621) - Sidetone
+ */
+#define WM8915_ST_LPF                           0x1000  /* ST_LPF */
+#define WM8915_ST_LPF_MASK                      0x1000  /* ST_LPF */
+#define WM8915_ST_LPF_SHIFT                         12  /* ST_LPF */
+#define WM8915_ST_LPF_WIDTH                          1  /* ST_LPF */
+#define WM8915_ST_HPF_CUT_MASK                  0x0380  /* ST_HPF_CUT - [9:7] */
+#define WM8915_ST_HPF_CUT_SHIFT                      7  /* ST_HPF_CUT - [9:7] */
+#define WM8915_ST_HPF_CUT_WIDTH                      3  /* ST_HPF_CUT - [9:7] */
+#define WM8915_ST_HPF                           0x0040  /* ST_HPF */
+#define WM8915_ST_HPF_MASK                      0x0040  /* ST_HPF */
+#define WM8915_ST_HPF_SHIFT                          6  /* ST_HPF */
+#define WM8915_ST_HPF_WIDTH                          1  /* ST_HPF */
+#define WM8915_STR_SEL                          0x0002  /* STR_SEL */
+#define WM8915_STR_SEL_MASK                     0x0002  /* STR_SEL */
+#define WM8915_STR_SEL_SHIFT                         1  /* STR_SEL */
+#define WM8915_STR_SEL_WIDTH                         1  /* STR_SEL */
+#define WM8915_STL_SEL                          0x0001  /* STL_SEL */
+#define WM8915_STL_SEL_MASK                     0x0001  /* STL_SEL */
+#define WM8915_STL_SEL_SHIFT                         0  /* STL_SEL */
+#define WM8915_STL_SEL_WIDTH                         1  /* STL_SEL */
+
+/*
+ * R1792 (0x700) - GPIO 1
+ */
+#define WM8915_GP1_DIR                          0x8000  /* GP1_DIR */
+#define WM8915_GP1_DIR_MASK                     0x8000  /* GP1_DIR */
+#define WM8915_GP1_DIR_SHIFT                        15  /* GP1_DIR */
+#define WM8915_GP1_DIR_WIDTH                         1  /* GP1_DIR */
+#define WM8915_GP1_PU                           0x4000  /* GP1_PU */
+#define WM8915_GP1_PU_MASK                      0x4000  /* GP1_PU */
+#define WM8915_GP1_PU_SHIFT                         14  /* GP1_PU */
+#define WM8915_GP1_PU_WIDTH                          1  /* GP1_PU */
+#define WM8915_GP1_PD                           0x2000  /* GP1_PD */
+#define WM8915_GP1_PD_MASK                      0x2000  /* GP1_PD */
+#define WM8915_GP1_PD_SHIFT                         13  /* GP1_PD */
+#define WM8915_GP1_PD_WIDTH                          1  /* GP1_PD */
+#define WM8915_GP1_POL                          0x0400  /* GP1_POL */
+#define WM8915_GP1_POL_MASK                     0x0400  /* GP1_POL */
+#define WM8915_GP1_POL_SHIFT                        10  /* GP1_POL */
+#define WM8915_GP1_POL_WIDTH                         1  /* GP1_POL */
+#define WM8915_GP1_OP_CFG                       0x0200  /* GP1_OP_CFG */
+#define WM8915_GP1_OP_CFG_MASK                  0x0200  /* GP1_OP_CFG */
+#define WM8915_GP1_OP_CFG_SHIFT                      9  /* GP1_OP_CFG */
+#define WM8915_GP1_OP_CFG_WIDTH                      1  /* GP1_OP_CFG */
+#define WM8915_GP1_DB                           0x0100  /* GP1_DB */
+#define WM8915_GP1_DB_MASK                      0x0100  /* GP1_DB */
+#define WM8915_GP1_DB_SHIFT                          8  /* GP1_DB */
+#define WM8915_GP1_DB_WIDTH                          1  /* GP1_DB */
+#define WM8915_GP1_LVL                          0x0040  /* GP1_LVL */
+#define WM8915_GP1_LVL_MASK                     0x0040  /* GP1_LVL */
+#define WM8915_GP1_LVL_SHIFT                         6  /* GP1_LVL */
+#define WM8915_GP1_LVL_WIDTH                         1  /* GP1_LVL */
+#define WM8915_GP1_FN_MASK                      0x000F  /* GP1_FN - [3:0] */
+#define WM8915_GP1_FN_SHIFT                          0  /* GP1_FN - [3:0] */
+#define WM8915_GP1_FN_WIDTH                          4  /* GP1_FN - [3:0] */
+
+/*
+ * R1793 (0x701) - GPIO 2
+ */
+#define WM8915_GP2_DIR                          0x8000  /* GP2_DIR */
+#define WM8915_GP2_DIR_MASK                     0x8000  /* GP2_DIR */
+#define WM8915_GP2_DIR_SHIFT                        15  /* GP2_DIR */
+#define WM8915_GP2_DIR_WIDTH                         1  /* GP2_DIR */
+#define WM8915_GP2_PU                           0x4000  /* GP2_PU */
+#define WM8915_GP2_PU_MASK                      0x4000  /* GP2_PU */
+#define WM8915_GP2_PU_SHIFT                         14  /* GP2_PU */
+#define WM8915_GP2_PU_WIDTH                          1  /* GP2_PU */
+#define WM8915_GP2_PD                           0x2000  /* GP2_PD */
+#define WM8915_GP2_PD_MASK                      0x2000  /* GP2_PD */
+#define WM8915_GP2_PD_SHIFT                         13  /* GP2_PD */
+#define WM8915_GP2_PD_WIDTH                          1  /* GP2_PD */
+#define WM8915_GP2_POL                          0x0400  /* GP2_POL */
+#define WM8915_GP2_POL_MASK                     0x0400  /* GP2_POL */
+#define WM8915_GP2_POL_SHIFT                        10  /* GP2_POL */
+#define WM8915_GP2_POL_WIDTH                         1  /* GP2_POL */
+#define WM8915_GP2_OP_CFG                       0x0200  /* GP2_OP_CFG */
+#define WM8915_GP2_OP_CFG_MASK                  0x0200  /* GP2_OP_CFG */
+#define WM8915_GP2_OP_CFG_SHIFT                      9  /* GP2_OP_CFG */
+#define WM8915_GP2_OP_CFG_WIDTH                      1  /* GP2_OP_CFG */
+#define WM8915_GP2_DB                           0x0100  /* GP2_DB */
+#define WM8915_GP2_DB_MASK                      0x0100  /* GP2_DB */
+#define WM8915_GP2_DB_SHIFT                          8  /* GP2_DB */
+#define WM8915_GP2_DB_WIDTH                          1  /* GP2_DB */
+#define WM8915_GP2_LVL                          0x0040  /* GP2_LVL */
+#define WM8915_GP2_LVL_MASK                     0x0040  /* GP2_LVL */
+#define WM8915_GP2_LVL_SHIFT                         6  /* GP2_LVL */
+#define WM8915_GP2_LVL_WIDTH                         1  /* GP2_LVL */
+#define WM8915_GP2_FN_MASK                      0x000F  /* GP2_FN - [3:0] */
+#define WM8915_GP2_FN_SHIFT                          0  /* GP2_FN - [3:0] */
+#define WM8915_GP2_FN_WIDTH                          4  /* GP2_FN - [3:0] */
+
+/*
+ * R1794 (0x702) - GPIO 3
+ */
+#define WM8915_GP3_DIR                          0x8000  /* GP3_DIR */
+#define WM8915_GP3_DIR_MASK                     0x8000  /* GP3_DIR */
+#define WM8915_GP3_DIR_SHIFT                        15  /* GP3_DIR */
+#define WM8915_GP3_DIR_WIDTH                         1  /* GP3_DIR */
+#define WM8915_GP3_PU                           0x4000  /* GP3_PU */
+#define WM8915_GP3_PU_MASK                      0x4000  /* GP3_PU */
+#define WM8915_GP3_PU_SHIFT                         14  /* GP3_PU */
+#define WM8915_GP3_PU_WIDTH                          1  /* GP3_PU */
+#define WM8915_GP3_PD                           0x2000  /* GP3_PD */
+#define WM8915_GP3_PD_MASK                      0x2000  /* GP3_PD */
+#define WM8915_GP3_PD_SHIFT                         13  /* GP3_PD */
+#define WM8915_GP3_PD_WIDTH                          1  /* GP3_PD */
+#define WM8915_GP3_POL                          0x0400  /* GP3_POL */
+#define WM8915_GP3_POL_MASK                     0x0400  /* GP3_POL */
+#define WM8915_GP3_POL_SHIFT                        10  /* GP3_POL */
+#define WM8915_GP3_POL_WIDTH                         1  /* GP3_POL */
+#define WM8915_GP3_OP_CFG                       0x0200  /* GP3_OP_CFG */
+#define WM8915_GP3_OP_CFG_MASK                  0x0200  /* GP3_OP_CFG */
+#define WM8915_GP3_OP_CFG_SHIFT                      9  /* GP3_OP_CFG */
+#define WM8915_GP3_OP_CFG_WIDTH                      1  /* GP3_OP_CFG */
+#define WM8915_GP3_DB                           0x0100  /* GP3_DB */
+#define WM8915_GP3_DB_MASK                      0x0100  /* GP3_DB */
+#define WM8915_GP3_DB_SHIFT                          8  /* GP3_DB */
+#define WM8915_GP3_DB_WIDTH                          1  /* GP3_DB */
+#define WM8915_GP3_LVL                          0x0040  /* GP3_LVL */
+#define WM8915_GP3_LVL_MASK                     0x0040  /* GP3_LVL */
+#define WM8915_GP3_LVL_SHIFT                         6  /* GP3_LVL */
+#define WM8915_GP3_LVL_WIDTH                         1  /* GP3_LVL */
+#define WM8915_GP3_FN_MASK                      0x000F  /* GP3_FN - [3:0] */
+#define WM8915_GP3_FN_SHIFT                          0  /* GP3_FN - [3:0] */
+#define WM8915_GP3_FN_WIDTH                          4  /* GP3_FN - [3:0] */
+
+/*
+ * R1795 (0x703) - GPIO 4
+ */
+#define WM8915_GP4_DIR                          0x8000  /* GP4_DIR */
+#define WM8915_GP4_DIR_MASK                     0x8000  /* GP4_DIR */
+#define WM8915_GP4_DIR_SHIFT                        15  /* GP4_DIR */
+#define WM8915_GP4_DIR_WIDTH                         1  /* GP4_DIR */
+#define WM8915_GP4_PU                           0x4000  /* GP4_PU */
+#define WM8915_GP4_PU_MASK                      0x4000  /* GP4_PU */
+#define WM8915_GP4_PU_SHIFT                         14  /* GP4_PU */
+#define WM8915_GP4_PU_WIDTH                          1  /* GP4_PU */
+#define WM8915_GP4_PD                           0x2000  /* GP4_PD */
+#define WM8915_GP4_PD_MASK                      0x2000  /* GP4_PD */
+#define WM8915_GP4_PD_SHIFT                         13  /* GP4_PD */
+#define WM8915_GP4_PD_WIDTH                          1  /* GP4_PD */
+#define WM8915_GP4_POL                          0x0400  /* GP4_POL */
+#define WM8915_GP4_POL_MASK                     0x0400  /* GP4_POL */
+#define WM8915_GP4_POL_SHIFT                        10  /* GP4_POL */
+#define WM8915_GP4_POL_WIDTH                         1  /* GP4_POL */
+#define WM8915_GP4_OP_CFG                       0x0200  /* GP4_OP_CFG */
+#define WM8915_GP4_OP_CFG_MASK                  0x0200  /* GP4_OP_CFG */
+#define WM8915_GP4_OP_CFG_SHIFT                      9  /* GP4_OP_CFG */
+#define WM8915_GP4_OP_CFG_WIDTH                      1  /* GP4_OP_CFG */
+#define WM8915_GP4_DB                           0x0100  /* GP4_DB */
+#define WM8915_GP4_DB_MASK                      0x0100  /* GP4_DB */
+#define WM8915_GP4_DB_SHIFT                          8  /* GP4_DB */
+#define WM8915_GP4_DB_WIDTH                          1  /* GP4_DB */
+#define WM8915_GP4_LVL                          0x0040  /* GP4_LVL */
+#define WM8915_GP4_LVL_MASK                     0x0040  /* GP4_LVL */
+#define WM8915_GP4_LVL_SHIFT                         6  /* GP4_LVL */
+#define WM8915_GP4_LVL_WIDTH                         1  /* GP4_LVL */
+#define WM8915_GP4_FN_MASK                      0x000F  /* GP4_FN - [3:0] */
+#define WM8915_GP4_FN_SHIFT                          0  /* GP4_FN - [3:0] */
+#define WM8915_GP4_FN_WIDTH                          4  /* GP4_FN - [3:0] */
+
+/*
+ * R1796 (0x704) - GPIO 5
+ */
+#define WM8915_GP5_DIR                          0x8000  /* GP5_DIR */
+#define WM8915_GP5_DIR_MASK                     0x8000  /* GP5_DIR */
+#define WM8915_GP5_DIR_SHIFT                        15  /* GP5_DIR */
+#define WM8915_GP5_DIR_WIDTH                         1  /* GP5_DIR */
+#define WM8915_GP5_PU                           0x4000  /* GP5_PU */
+#define WM8915_GP5_PU_MASK                      0x4000  /* GP5_PU */
+#define WM8915_GP5_PU_SHIFT                         14  /* GP5_PU */
+#define WM8915_GP5_PU_WIDTH                          1  /* GP5_PU */
+#define WM8915_GP5_PD                           0x2000  /* GP5_PD */
+#define WM8915_GP5_PD_MASK                      0x2000  /* GP5_PD */
+#define WM8915_GP5_PD_SHIFT                         13  /* GP5_PD */
+#define WM8915_GP5_PD_WIDTH                          1  /* GP5_PD */
+#define WM8915_GP5_POL                          0x0400  /* GP5_POL */
+#define WM8915_GP5_POL_MASK                     0x0400  /* GP5_POL */
+#define WM8915_GP5_POL_SHIFT                        10  /* GP5_POL */
+#define WM8915_GP5_POL_WIDTH                         1  /* GP5_POL */
+#define WM8915_GP5_OP_CFG                       0x0200  /* GP5_OP_CFG */
+#define WM8915_GP5_OP_CFG_MASK                  0x0200  /* GP5_OP_CFG */
+#define WM8915_GP5_OP_CFG_SHIFT                      9  /* GP5_OP_CFG */
+#define WM8915_GP5_OP_CFG_WIDTH                      1  /* GP5_OP_CFG */
+#define WM8915_GP5_DB                           0x0100  /* GP5_DB */
+#define WM8915_GP5_DB_MASK                      0x0100  /* GP5_DB */
+#define WM8915_GP5_DB_SHIFT                          8  /* GP5_DB */
+#define WM8915_GP5_DB_WIDTH                          1  /* GP5_DB */
+#define WM8915_GP5_LVL                          0x0040  /* GP5_LVL */
+#define WM8915_GP5_LVL_MASK                     0x0040  /* GP5_LVL */
+#define WM8915_GP5_LVL_SHIFT                         6  /* GP5_LVL */
+#define WM8915_GP5_LVL_WIDTH                         1  /* GP5_LVL */
+#define WM8915_GP5_FN_MASK                      0x000F  /* GP5_FN - [3:0] */
+#define WM8915_GP5_FN_SHIFT                          0  /* GP5_FN - [3:0] */
+#define WM8915_GP5_FN_WIDTH                          4  /* GP5_FN - [3:0] */
+
+/*
+ * R1824 (0x720) - Pull Control (1)
+ */
+#define WM8915_DMICDAT2_PD                      0x1000  /* DMICDAT2_PD */
+#define WM8915_DMICDAT2_PD_MASK                 0x1000  /* DMICDAT2_PD */
+#define WM8915_DMICDAT2_PD_SHIFT                    12  /* DMICDAT2_PD */
+#define WM8915_DMICDAT2_PD_WIDTH                     1  /* DMICDAT2_PD */
+#define WM8915_DMICDAT1_PD                      0x0400  /* DMICDAT1_PD */
+#define WM8915_DMICDAT1_PD_MASK                 0x0400  /* DMICDAT1_PD */
+#define WM8915_DMICDAT1_PD_SHIFT                    10  /* DMICDAT1_PD */
+#define WM8915_DMICDAT1_PD_WIDTH                     1  /* DMICDAT1_PD */
+#define WM8915_MCLK2_PU                         0x0200  /* MCLK2_PU */
+#define WM8915_MCLK2_PU_MASK                    0x0200  /* MCLK2_PU */
+#define WM8915_MCLK2_PU_SHIFT                        9  /* MCLK2_PU */
+#define WM8915_MCLK2_PU_WIDTH                        1  /* MCLK2_PU */
+#define WM8915_MCLK2_PD                         0x0100  /* MCLK2_PD */
+#define WM8915_MCLK2_PD_MASK                    0x0100  /* MCLK2_PD */
+#define WM8915_MCLK2_PD_SHIFT                        8  /* MCLK2_PD */
+#define WM8915_MCLK2_PD_WIDTH                        1  /* MCLK2_PD */
+#define WM8915_MCLK1_PU                         0x0080  /* MCLK1_PU */
+#define WM8915_MCLK1_PU_MASK                    0x0080  /* MCLK1_PU */
+#define WM8915_MCLK1_PU_SHIFT                        7  /* MCLK1_PU */
+#define WM8915_MCLK1_PU_WIDTH                        1  /* MCLK1_PU */
+#define WM8915_MCLK1_PD                         0x0040  /* MCLK1_PD */
+#define WM8915_MCLK1_PD_MASK                    0x0040  /* MCLK1_PD */
+#define WM8915_MCLK1_PD_SHIFT                        6  /* MCLK1_PD */
+#define WM8915_MCLK1_PD_WIDTH                        1  /* MCLK1_PD */
+#define WM8915_DACDAT1_PU                       0x0020  /* DACDAT1_PU */
+#define WM8915_DACDAT1_PU_MASK                  0x0020  /* DACDAT1_PU */
+#define WM8915_DACDAT1_PU_SHIFT                      5  /* DACDAT1_PU */
+#define WM8915_DACDAT1_PU_WIDTH                      1  /* DACDAT1_PU */
+#define WM8915_DACDAT1_PD                       0x0010  /* DACDAT1_PD */
+#define WM8915_DACDAT1_PD_MASK                  0x0010  /* DACDAT1_PD */
+#define WM8915_DACDAT1_PD_SHIFT                      4  /* DACDAT1_PD */
+#define WM8915_DACDAT1_PD_WIDTH                      1  /* DACDAT1_PD */
+#define WM8915_DACLRCLK1_PU                     0x0008  /* DACLRCLK1_PU */
+#define WM8915_DACLRCLK1_PU_MASK                0x0008  /* DACLRCLK1_PU */
+#define WM8915_DACLRCLK1_PU_SHIFT                    3  /* DACLRCLK1_PU */
+#define WM8915_DACLRCLK1_PU_WIDTH                    1  /* DACLRCLK1_PU */
+#define WM8915_DACLRCLK1_PD                     0x0004  /* DACLRCLK1_PD */
+#define WM8915_DACLRCLK1_PD_MASK                0x0004  /* DACLRCLK1_PD */
+#define WM8915_DACLRCLK1_PD_SHIFT                    2  /* DACLRCLK1_PD */
+#define WM8915_DACLRCLK1_PD_WIDTH                    1  /* DACLRCLK1_PD */
+#define WM8915_BCLK1_PU                         0x0002  /* BCLK1_PU */
+#define WM8915_BCLK1_PU_MASK                    0x0002  /* BCLK1_PU */
+#define WM8915_BCLK1_PU_SHIFT                        1  /* BCLK1_PU */
+#define WM8915_BCLK1_PU_WIDTH                        1  /* BCLK1_PU */
+#define WM8915_BCLK1_PD                         0x0001  /* BCLK1_PD */
+#define WM8915_BCLK1_PD_MASK                    0x0001  /* BCLK1_PD */
+#define WM8915_BCLK1_PD_SHIFT                        0  /* BCLK1_PD */
+#define WM8915_BCLK1_PD_WIDTH                        1  /* BCLK1_PD */
+
+/*
+ * R1825 (0x721) - Pull Control (2)
+ */
+#define WM8915_LDO1ENA_PD                       0x0100  /* LDO1ENA_PD */
+#define WM8915_LDO1ENA_PD_MASK                  0x0100  /* LDO1ENA_PD */
+#define WM8915_LDO1ENA_PD_SHIFT                      8  /* LDO1ENA_PD */
+#define WM8915_LDO1ENA_PD_WIDTH                      1  /* LDO1ENA_PD */
+#define WM8915_ADDR_PD                          0x0040  /* ADDR_PD */
+#define WM8915_ADDR_PD_MASK                     0x0040  /* ADDR_PD */
+#define WM8915_ADDR_PD_SHIFT                         6  /* ADDR_PD */
+#define WM8915_ADDR_PD_WIDTH                         1  /* ADDR_PD */
+#define WM8915_DACDAT2_PU                       0x0020  /* DACDAT2_PU */
+#define WM8915_DACDAT2_PU_MASK                  0x0020  /* DACDAT2_PU */
+#define WM8915_DACDAT2_PU_SHIFT                      5  /* DACDAT2_PU */
+#define WM8915_DACDAT2_PU_WIDTH                      1  /* DACDAT2_PU */
+#define WM8915_DACDAT2_PD                       0x0010  /* DACDAT2_PD */
+#define WM8915_DACDAT2_PD_MASK                  0x0010  /* DACDAT2_PD */
+#define WM8915_DACDAT2_PD_SHIFT                      4  /* DACDAT2_PD */
+#define WM8915_DACDAT2_PD_WIDTH                      1  /* DACDAT2_PD */
+#define WM8915_DACLRCLK2_PU                     0x0008  /* DACLRCLK2_PU */
+#define WM8915_DACLRCLK2_PU_MASK                0x0008  /* DACLRCLK2_PU */
+#define WM8915_DACLRCLK2_PU_SHIFT                    3  /* DACLRCLK2_PU */
+#define WM8915_DACLRCLK2_PU_WIDTH                    1  /* DACLRCLK2_PU */
+#define WM8915_DACLRCLK2_PD                     0x0004  /* DACLRCLK2_PD */
+#define WM8915_DACLRCLK2_PD_MASK                0x0004  /* DACLRCLK2_PD */
+#define WM8915_DACLRCLK2_PD_SHIFT                    2  /* DACLRCLK2_PD */
+#define WM8915_DACLRCLK2_PD_WIDTH                    1  /* DACLRCLK2_PD */
+#define WM8915_BCLK2_PU                         0x0002  /* BCLK2_PU */
+#define WM8915_BCLK2_PU_MASK                    0x0002  /* BCLK2_PU */
+#define WM8915_BCLK2_PU_SHIFT                        1  /* BCLK2_PU */
+#define WM8915_BCLK2_PU_WIDTH                        1  /* BCLK2_PU */
+#define WM8915_BCLK2_PD                         0x0001  /* BCLK2_PD */
+#define WM8915_BCLK2_PD_MASK                    0x0001  /* BCLK2_PD */
+#define WM8915_BCLK2_PD_SHIFT                        0  /* BCLK2_PD */
+#define WM8915_BCLK2_PD_WIDTH                        1  /* BCLK2_PD */
+
+/*
+ * R1840 (0x730) - Interrupt Status 1
+ */
+#define WM8915_GP5_EINT                         0x0010  /* GP5_EINT */
+#define WM8915_GP5_EINT_MASK                    0x0010  /* GP5_EINT */
+#define WM8915_GP5_EINT_SHIFT                        4  /* GP5_EINT */
+#define WM8915_GP5_EINT_WIDTH                        1  /* GP5_EINT */
+#define WM8915_GP4_EINT                         0x0008  /* GP4_EINT */
+#define WM8915_GP4_EINT_MASK                    0x0008  /* GP4_EINT */
+#define WM8915_GP4_EINT_SHIFT                        3  /* GP4_EINT */
+#define WM8915_GP4_EINT_WIDTH                        1  /* GP4_EINT */
+#define WM8915_GP3_EINT                         0x0004  /* GP3_EINT */
+#define WM8915_GP3_EINT_MASK                    0x0004  /* GP3_EINT */
+#define WM8915_GP3_EINT_SHIFT                        2  /* GP3_EINT */
+#define WM8915_GP3_EINT_WIDTH                        1  /* GP3_EINT */
+#define WM8915_GP2_EINT                         0x0002  /* GP2_EINT */
+#define WM8915_GP2_EINT_MASK                    0x0002  /* GP2_EINT */
+#define WM8915_GP2_EINT_SHIFT                        1  /* GP2_EINT */
+#define WM8915_GP2_EINT_WIDTH                        1  /* GP2_EINT */
+#define WM8915_GP1_EINT                         0x0001  /* GP1_EINT */
+#define WM8915_GP1_EINT_MASK                    0x0001  /* GP1_EINT */
+#define WM8915_GP1_EINT_SHIFT                        0  /* GP1_EINT */
+#define WM8915_GP1_EINT_WIDTH                        1  /* GP1_EINT */
+
+/*
+ * R1841 (0x731) - Interrupt Status 2
+ */
+#define WM8915_DCS_DONE_23_EINT                 0x1000  /* DCS_DONE_23_EINT */
+#define WM8915_DCS_DONE_23_EINT_MASK            0x1000  /* DCS_DONE_23_EINT */
+#define WM8915_DCS_DONE_23_EINT_SHIFT               12  /* DCS_DONE_23_EINT */
+#define WM8915_DCS_DONE_23_EINT_WIDTH                1  /* DCS_DONE_23_EINT */
+#define WM8915_DCS_DONE_01_EINT                 0x0800  /* DCS_DONE_01_EINT */
+#define WM8915_DCS_DONE_01_EINT_MASK            0x0800  /* DCS_DONE_01_EINT */
+#define WM8915_DCS_DONE_01_EINT_SHIFT               11  /* DCS_DONE_01_EINT */
+#define WM8915_DCS_DONE_01_EINT_WIDTH                1  /* DCS_DONE_01_EINT */
+#define WM8915_WSEQ_DONE_EINT                   0x0400  /* WSEQ_DONE_EINT */
+#define WM8915_WSEQ_DONE_EINT_MASK              0x0400  /* WSEQ_DONE_EINT */
+#define WM8915_WSEQ_DONE_EINT_SHIFT                 10  /* WSEQ_DONE_EINT */
+#define WM8915_WSEQ_DONE_EINT_WIDTH                  1  /* WSEQ_DONE_EINT */
+#define WM8915_FIFOS_ERR_EINT                   0x0200  /* FIFOS_ERR_EINT */
+#define WM8915_FIFOS_ERR_EINT_MASK              0x0200  /* FIFOS_ERR_EINT */
+#define WM8915_FIFOS_ERR_EINT_SHIFT                  9  /* FIFOS_ERR_EINT */
+#define WM8915_FIFOS_ERR_EINT_WIDTH                  1  /* FIFOS_ERR_EINT */
+#define WM8915_DSP2DRC_SIG_DET_EINT             0x0080  /* DSP2DRC_SIG_DET_EINT */
+#define WM8915_DSP2DRC_SIG_DET_EINT_MASK        0x0080  /* DSP2DRC_SIG_DET_EINT */
+#define WM8915_DSP2DRC_SIG_DET_EINT_SHIFT            7  /* DSP2DRC_SIG_DET_EINT */
+#define WM8915_DSP2DRC_SIG_DET_EINT_WIDTH            1  /* DSP2DRC_SIG_DET_EINT */
+#define WM8915_DSP1DRC_SIG_DET_EINT             0x0040  /* DSP1DRC_SIG_DET_EINT */
+#define WM8915_DSP1DRC_SIG_DET_EINT_MASK        0x0040  /* DSP1DRC_SIG_DET_EINT */
+#define WM8915_DSP1DRC_SIG_DET_EINT_SHIFT            6  /* DSP1DRC_SIG_DET_EINT */
+#define WM8915_DSP1DRC_SIG_DET_EINT_WIDTH            1  /* DSP1DRC_SIG_DET_EINT */
+#define WM8915_FLL_SW_CLK_DONE_EINT             0x0008  /* FLL_SW_CLK_DONE_EINT */
+#define WM8915_FLL_SW_CLK_DONE_EINT_MASK        0x0008  /* FLL_SW_CLK_DONE_EINT */
+#define WM8915_FLL_SW_CLK_DONE_EINT_SHIFT            3  /* FLL_SW_CLK_DONE_EINT */
+#define WM8915_FLL_SW_CLK_DONE_EINT_WIDTH            1  /* FLL_SW_CLK_DONE_EINT */
+#define WM8915_FLL_LOCK_EINT                    0x0004  /* FLL_LOCK_EINT */
+#define WM8915_FLL_LOCK_EINT_MASK               0x0004  /* FLL_LOCK_EINT */
+#define WM8915_FLL_LOCK_EINT_SHIFT                   2  /* FLL_LOCK_EINT */
+#define WM8915_FLL_LOCK_EINT_WIDTH                   1  /* FLL_LOCK_EINT */
+#define WM8915_HP_DONE_EINT                     0x0002  /* HP_DONE_EINT */
+#define WM8915_HP_DONE_EINT_MASK                0x0002  /* HP_DONE_EINT */
+#define WM8915_HP_DONE_EINT_SHIFT                    1  /* HP_DONE_EINT */
+#define WM8915_HP_DONE_EINT_WIDTH                    1  /* HP_DONE_EINT */
+#define WM8915_MICD_EINT                        0x0001  /* MICD_EINT */
+#define WM8915_MICD_EINT_MASK                   0x0001  /* MICD_EINT */
+#define WM8915_MICD_EINT_SHIFT                       0  /* MICD_EINT */
+#define WM8915_MICD_EINT_WIDTH                       1  /* MICD_EINT */
+
+/*
+ * R1842 (0x732) - Interrupt Raw Status 2
+ */
+#define WM8915_DCS_DONE_23_STS                  0x1000  /* DCS_DONE_23_STS */
+#define WM8915_DCS_DONE_23_STS_MASK             0x1000  /* DCS_DONE_23_STS */
+#define WM8915_DCS_DONE_23_STS_SHIFT                12  /* DCS_DONE_23_STS */
+#define WM8915_DCS_DONE_23_STS_WIDTH                 1  /* DCS_DONE_23_STS */
+#define WM8915_DCS_DONE_01_STS                  0x0800  /* DCS_DONE_01_STS */
+#define WM8915_DCS_DONE_01_STS_MASK             0x0800  /* DCS_DONE_01_STS */
+#define WM8915_DCS_DONE_01_STS_SHIFT                11  /* DCS_DONE_01_STS */
+#define WM8915_DCS_DONE_01_STS_WIDTH                 1  /* DCS_DONE_01_STS */
+#define WM8915_WSEQ_DONE_STS                    0x0400  /* WSEQ_DONE_STS */
+#define WM8915_WSEQ_DONE_STS_MASK               0x0400  /* WSEQ_DONE_STS */
+#define WM8915_WSEQ_DONE_STS_SHIFT                  10  /* WSEQ_DONE_STS */
+#define WM8915_WSEQ_DONE_STS_WIDTH                   1  /* WSEQ_DONE_STS */
+#define WM8915_FIFOS_ERR_STS                    0x0200  /* FIFOS_ERR_STS */
+#define WM8915_FIFOS_ERR_STS_MASK               0x0200  /* FIFOS_ERR_STS */
+#define WM8915_FIFOS_ERR_STS_SHIFT                   9  /* FIFOS_ERR_STS */
+#define WM8915_FIFOS_ERR_STS_WIDTH                   1  /* FIFOS_ERR_STS */
+#define WM8915_DSP2DRC_SIG_DET_STS              0x0080  /* DSP2DRC_SIG_DET_STS */
+#define WM8915_DSP2DRC_SIG_DET_STS_MASK         0x0080  /* DSP2DRC_SIG_DET_STS */
+#define WM8915_DSP2DRC_SIG_DET_STS_SHIFT             7  /* DSP2DRC_SIG_DET_STS */
+#define WM8915_DSP2DRC_SIG_DET_STS_WIDTH             1  /* DSP2DRC_SIG_DET_STS */
+#define WM8915_DSP1DRC_SIG_DET_STS              0x0040  /* DSP1DRC_SIG_DET_STS */
+#define WM8915_DSP1DRC_SIG_DET_STS_MASK         0x0040  /* DSP1DRC_SIG_DET_STS */
+#define WM8915_DSP1DRC_SIG_DET_STS_SHIFT             6  /* DSP1DRC_SIG_DET_STS */
+#define WM8915_DSP1DRC_SIG_DET_STS_WIDTH             1  /* DSP1DRC_SIG_DET_STS */
+#define WM8915_FLL_LOCK_STS                     0x0004  /* FLL_LOCK_STS */
+#define WM8915_FLL_LOCK_STS_MASK                0x0004  /* FLL_LOCK_STS */
+#define WM8915_FLL_LOCK_STS_SHIFT                    2  /* FLL_LOCK_STS */
+#define WM8915_FLL_LOCK_STS_WIDTH                    1  /* FLL_LOCK_STS */
+
+/*
+ * R1848 (0x738) - Interrupt Status 1 Mask
+ */
+#define WM8915_IM_GP5_EINT                      0x0010  /* IM_GP5_EINT */
+#define WM8915_IM_GP5_EINT_MASK                 0x0010  /* IM_GP5_EINT */
+#define WM8915_IM_GP5_EINT_SHIFT                     4  /* IM_GP5_EINT */
+#define WM8915_IM_GP5_EINT_WIDTH                     1  /* IM_GP5_EINT */
+#define WM8915_IM_GP4_EINT                      0x0008  /* IM_GP4_EINT */
+#define WM8915_IM_GP4_EINT_MASK                 0x0008  /* IM_GP4_EINT */
+#define WM8915_IM_GP4_EINT_SHIFT                     3  /* IM_GP4_EINT */
+#define WM8915_IM_GP4_EINT_WIDTH                     1  /* IM_GP4_EINT */
+#define WM8915_IM_GP3_EINT                      0x0004  /* IM_GP3_EINT */
+#define WM8915_IM_GP3_EINT_MASK                 0x0004  /* IM_GP3_EINT */
+#define WM8915_IM_GP3_EINT_SHIFT                     2  /* IM_GP3_EINT */
+#define WM8915_IM_GP3_EINT_WIDTH                     1  /* IM_GP3_EINT */
+#define WM8915_IM_GP2_EINT                      0x0002  /* IM_GP2_EINT */
+#define WM8915_IM_GP2_EINT_MASK                 0x0002  /* IM_GP2_EINT */
+#define WM8915_IM_GP2_EINT_SHIFT                     1  /* IM_GP2_EINT */
+#define WM8915_IM_GP2_EINT_WIDTH                     1  /* IM_GP2_EINT */
+#define WM8915_IM_GP1_EINT                      0x0001  /* IM_GP1_EINT */
+#define WM8915_IM_GP1_EINT_MASK                 0x0001  /* IM_GP1_EINT */
+#define WM8915_IM_GP1_EINT_SHIFT                     0  /* IM_GP1_EINT */
+#define WM8915_IM_GP1_EINT_WIDTH                     1  /* IM_GP1_EINT */
+
+/*
+ * R1849 (0x739) - Interrupt Status 2 Mask
+ */
+#define WM8915_IM_DCS_DONE_23_EINT              0x1000  /* IM_DCS_DONE_23_EINT */
+#define WM8915_IM_DCS_DONE_23_EINT_MASK         0x1000  /* IM_DCS_DONE_23_EINT */
+#define WM8915_IM_DCS_DONE_23_EINT_SHIFT            12  /* IM_DCS_DONE_23_EINT */
+#define WM8915_IM_DCS_DONE_23_EINT_WIDTH             1  /* IM_DCS_DONE_23_EINT */
+#define WM8915_IM_DCS_DONE_01_EINT              0x0800  /* IM_DCS_DONE_01_EINT */
+#define WM8915_IM_DCS_DONE_01_EINT_MASK         0x0800  /* IM_DCS_DONE_01_EINT */
+#define WM8915_IM_DCS_DONE_01_EINT_SHIFT            11  /* IM_DCS_DONE_01_EINT */
+#define WM8915_IM_DCS_DONE_01_EINT_WIDTH             1  /* IM_DCS_DONE_01_EINT */
+#define WM8915_IM_WSEQ_DONE_EINT                0x0400  /* IM_WSEQ_DONE_EINT */
+#define WM8915_IM_WSEQ_DONE_EINT_MASK           0x0400  /* IM_WSEQ_DONE_EINT */
+#define WM8915_IM_WSEQ_DONE_EINT_SHIFT              10  /* IM_WSEQ_DONE_EINT */
+#define WM8915_IM_WSEQ_DONE_EINT_WIDTH               1  /* IM_WSEQ_DONE_EINT */
+#define WM8915_IM_FIFOS_ERR_EINT                0x0200  /* IM_FIFOS_ERR_EINT */
+#define WM8915_IM_FIFOS_ERR_EINT_MASK           0x0200  /* IM_FIFOS_ERR_EINT */
+#define WM8915_IM_FIFOS_ERR_EINT_SHIFT               9  /* IM_FIFOS_ERR_EINT */
+#define WM8915_IM_FIFOS_ERR_EINT_WIDTH               1  /* IM_FIFOS_ERR_EINT */
+#define WM8915_IM_DSP2DRC_SIG_DET_EINT          0x0080  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8915_IM_DSP2DRC_SIG_DET_EINT_MASK     0x0080  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8915_IM_DSP2DRC_SIG_DET_EINT_SHIFT         7  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8915_IM_DSP2DRC_SIG_DET_EINT_WIDTH         1  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8915_IM_DSP1DRC_SIG_DET_EINT          0x0040  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8915_IM_DSP1DRC_SIG_DET_EINT_MASK     0x0040  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8915_IM_DSP1DRC_SIG_DET_EINT_SHIFT         6  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8915_IM_DSP1DRC_SIG_DET_EINT_WIDTH         1  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8915_IM_FLL_SW_CLK_DONE_EINT          0x0008  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8915_IM_FLL_SW_CLK_DONE_EINT_MASK     0x0008  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8915_IM_FLL_SW_CLK_DONE_EINT_SHIFT         3  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8915_IM_FLL_SW_CLK_DONE_EINT_WIDTH         1  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8915_IM_FLL_LOCK_EINT                 0x0004  /* IM_FLL_LOCK_EINT */
+#define WM8915_IM_FLL_LOCK_EINT_MASK            0x0004  /* IM_FLL_LOCK_EINT */
+#define WM8915_IM_FLL_LOCK_EINT_SHIFT                2  /* IM_FLL_LOCK_EINT */
+#define WM8915_IM_FLL_LOCK_EINT_WIDTH                1  /* IM_FLL_LOCK_EINT */
+#define WM8915_IM_HP_DONE_EINT                  0x0002  /* IM_HP_DONE_EINT */
+#define WM8915_IM_HP_DONE_EINT_MASK             0x0002  /* IM_HP_DONE_EINT */
+#define WM8915_IM_HP_DONE_EINT_SHIFT                 1  /* IM_HP_DONE_EINT */
+#define WM8915_IM_HP_DONE_EINT_WIDTH                 1  /* IM_HP_DONE_EINT */
+#define WM8915_IM_MICD_EINT                     0x0001  /* IM_MICD_EINT */
+#define WM8915_IM_MICD_EINT_MASK                0x0001  /* IM_MICD_EINT */
+#define WM8915_IM_MICD_EINT_SHIFT                    0  /* IM_MICD_EINT */
+#define WM8915_IM_MICD_EINT_WIDTH                    1  /* IM_MICD_EINT */
+
+/*
+ * R1856 (0x740) - Interrupt Control
+ */
+#define WM8915_IM_IRQ                           0x0001  /* IM_IRQ */
+#define WM8915_IM_IRQ_MASK                      0x0001  /* IM_IRQ */
+#define WM8915_IM_IRQ_SHIFT                          0  /* IM_IRQ */
+#define WM8915_IM_IRQ_WIDTH                          1  /* IM_IRQ */
+
+/*
+ * R2048 (0x800) - Left PDM Speaker
+ */
+#define WM8915_SPKL_ENA                         0x0010  /* SPKL_ENA */
+#define WM8915_SPKL_ENA_MASK                    0x0010  /* SPKL_ENA */
+#define WM8915_SPKL_ENA_SHIFT                        4  /* SPKL_ENA */
+#define WM8915_SPKL_ENA_WIDTH                        1  /* SPKL_ENA */
+#define WM8915_SPKL_MUTE                        0x0008  /* SPKL_MUTE */
+#define WM8915_SPKL_MUTE_MASK                   0x0008  /* SPKL_MUTE */
+#define WM8915_SPKL_MUTE_SHIFT                       3  /* SPKL_MUTE */
+#define WM8915_SPKL_MUTE_WIDTH                       1  /* SPKL_MUTE */
+#define WM8915_SPKL_MUTE_ZC                     0x0004  /* SPKL_MUTE_ZC */
+#define WM8915_SPKL_MUTE_ZC_MASK                0x0004  /* SPKL_MUTE_ZC */
+#define WM8915_SPKL_MUTE_ZC_SHIFT                    2  /* SPKL_MUTE_ZC */
+#define WM8915_SPKL_MUTE_ZC_WIDTH                    1  /* SPKL_MUTE_ZC */
+#define WM8915_SPKL_SRC_MASK                    0x0003  /* SPKL_SRC - [1:0] */
+#define WM8915_SPKL_SRC_SHIFT                        0  /* SPKL_SRC - [1:0] */
+#define WM8915_SPKL_SRC_WIDTH                        2  /* SPKL_SRC - [1:0] */
+
+/*
+ * R2049 (0x801) - Right PDM Speaker
+ */
+#define WM8915_SPKR_ENA                         0x0010  /* SPKR_ENA */
+#define WM8915_SPKR_ENA_MASK                    0x0010  /* SPKR_ENA */
+#define WM8915_SPKR_ENA_SHIFT                        4  /* SPKR_ENA */
+#define WM8915_SPKR_ENA_WIDTH                        1  /* SPKR_ENA */
+#define WM8915_SPKR_MUTE                        0x0008  /* SPKR_MUTE */
+#define WM8915_SPKR_MUTE_MASK                   0x0008  /* SPKR_MUTE */
+#define WM8915_SPKR_MUTE_SHIFT                       3  /* SPKR_MUTE */
+#define WM8915_SPKR_MUTE_WIDTH                       1  /* SPKR_MUTE */
+#define WM8915_SPKR_MUTE_ZC                     0x0004  /* SPKR_MUTE_ZC */
+#define WM8915_SPKR_MUTE_ZC_MASK                0x0004  /* SPKR_MUTE_ZC */
+#define WM8915_SPKR_MUTE_ZC_SHIFT                    2  /* SPKR_MUTE_ZC */
+#define WM8915_SPKR_MUTE_ZC_WIDTH                    1  /* SPKR_MUTE_ZC */
+#define WM8915_SPKR_SRC_MASK                    0x0003  /* SPKR_SRC - [1:0] */
+#define WM8915_SPKR_SRC_SHIFT                        0  /* SPKR_SRC - [1:0] */
+#define WM8915_SPKR_SRC_WIDTH                        2  /* SPKR_SRC - [1:0] */
+
+/*
+ * R2050 (0x802) - PDM Speaker Mute Sequence
+ */
+#define WM8915_SPK_MUTE_ENDIAN                  0x0100  /* SPK_MUTE_ENDIAN */
+#define WM8915_SPK_MUTE_ENDIAN_MASK             0x0100  /* SPK_MUTE_ENDIAN */
+#define WM8915_SPK_MUTE_ENDIAN_SHIFT                 8  /* SPK_MUTE_ENDIAN */
+#define WM8915_SPK_MUTE_ENDIAN_WIDTH                 1  /* SPK_MUTE_ENDIAN */
+#define WM8915_SPK_MUTE_SEQ1_MASK               0x00FF  /* SPK_MUTE_SEQ1 - [7:0] */
+#define WM8915_SPK_MUTE_SEQ1_SHIFT                   0  /* SPK_MUTE_SEQ1 - [7:0] */
+#define WM8915_SPK_MUTE_SEQ1_WIDTH                   8  /* SPK_MUTE_SEQ1 - [7:0] */
+
+/*
+ * R2051 (0x803) - PDM Speaker Volume
+ */
+#define WM8915_SPKR_VOL_MASK                    0x00F0  /* SPKR_VOL - [7:4] */
+#define WM8915_SPKR_VOL_SHIFT                        4  /* SPKR_VOL - [7:4] */
+#define WM8915_SPKR_VOL_WIDTH                        4  /* SPKR_VOL - [7:4] */
+#define WM8915_SPKL_VOL_MASK                    0x000F  /* SPKL_VOL - [3:0] */
+#define WM8915_SPKL_VOL_SHIFT                        0  /* SPKL_VOL - [3:0] */
+#define WM8915_SPKL_VOL_WIDTH                        4  /* SPKL_VOL - [3:0] */
+
+#endif
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c
new file mode 100644
index 000000000000..0293763debe5
--- /dev/null
+++ b/sound/soc/codecs/wm8958-dsp2.c
@@ -0,0 +1,1051 @@
+/*
+ * wm8958-dsp2.c  --  WM8958 DSP2 support
+ *
+ * Copyright 2011 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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.
+ */
+
+#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 <linux/slab.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <trace/events/asoc.h>
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+#include <linux/mfd/wm8994/pdata.h>
+#include <linux/mfd/wm8994/gpio.h>
+
+#include "wm8994.h"
+
+#define WM_FW_BLOCK_INFO 0xff
+#define WM_FW_BLOCK_PM   0x00
+#define WM_FW_BLOCK_X    0x01
+#define WM_FW_BLOCK_Y    0x02
+#define WM_FW_BLOCK_Z    0x03
+#define WM_FW_BLOCK_I    0x06
+#define WM_FW_BLOCK_A    0x08
+#define WM_FW_BLOCK_C    0x0c
+
+static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
+			  const struct firmware *fw, bool check)
+{
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	u64 data64;
+	u32 data32;
+	const u8 *data;
+	char *str;
+	size_t block_len, len;
+	int ret = 0;
+
+	/* Suppress unneeded downloads */
+	if (wm8994->cur_fw == fw)
+		return 0;
+
+	if (fw->size < 32) {
+		dev_err(codec->dev, "%s: firmware too short\n", name);
+		goto err;
+	}
+
+	if (memcmp(fw->data, "WMFW", 4) != 0) {
+		dev_err(codec->dev, "%s: firmware has bad file magic %08x\n",
+			name, data32);
+		goto err;
+	}
+
+	memcpy(&data32, fw->data + 4, sizeof(data32));
+	len = be32_to_cpu(data32);
+
+	memcpy(&data32, fw->data + 8, sizeof(data32));
+	data32 = be32_to_cpu(data32);
+	if ((data32 >> 24) & 0xff) {
+		dev_err(codec->dev, "%s: unsupported firmware version %d\n",
+			name, (data32 >> 24) & 0xff);
+		goto err;
+	}
+	if ((data32 & 0xffff) != 8958) {
+		dev_err(codec->dev, "%s: unsupported target device %d\n",
+			name, data32 & 0xffff);
+		goto err;
+	}
+	if (((data32 >> 16) & 0xff) != 0xc) {
+		dev_err(codec->dev, "%s: unsupported target core %d\n",
+			name, (data32 >> 16) & 0xff);
+		goto err;
+	}
+
+	if (check) {
+		memcpy(&data64, fw->data + 24, sizeof(u64));
+		dev_info(codec->dev, "%s timestamp %llx\n",
+			 name, be64_to_cpu(data64));
+	} else {
+		snd_soc_write(codec, 0x102, 0x2);
+		snd_soc_write(codec, 0x900, 0x2);
+	}
+
+	data = fw->data + len;
+	len = fw->size - len;
+	while (len) {
+		if (len < 12) {
+			dev_err(codec->dev, "%s short data block of %zd\n",
+				name, len);
+			goto err;
+		}
+
+		memcpy(&data32, data + 4, sizeof(data32));
+		block_len = be32_to_cpu(data32);
+		if (block_len + 8 > len) {
+			dev_err(codec->dev, "%zd byte block longer than file\n",
+				block_len);
+			goto err;
+		}
+		if (block_len == 0) {
+			dev_err(codec->dev, "Zero length block\n");
+			goto err;
+		}
+
+		memcpy(&data32, data, sizeof(data32));
+		data32 = be32_to_cpu(data32);
+
+		switch ((data32 >> 24) & 0xff) {
+		case WM_FW_BLOCK_INFO:
+			/* Informational text */
+			if (!check)
+				break;
+
+			str = kzalloc(block_len + 1, GFP_KERNEL);
+			if (str) {
+				memcpy(str, data + 8, block_len);
+				dev_info(codec->dev, "%s: %s\n", name, str);
+				kfree(str);
+			} else {
+				dev_err(codec->dev, "Out of memory\n");
+			}
+			break;
+		case WM_FW_BLOCK_PM:
+		case WM_FW_BLOCK_X:
+		case WM_FW_BLOCK_Y:
+		case WM_FW_BLOCK_Z:
+		case WM_FW_BLOCK_I:
+		case WM_FW_BLOCK_A:
+		case WM_FW_BLOCK_C:
+			dev_dbg(codec->dev, "%s: %zd bytes of %x@%x\n", name,
+				block_len, (data32 >> 24) & 0xff,
+				data32 & 0xffffff);
+
+			if (check)
+				break;
+
+			data32 &= 0xffffff;
+
+			wm8994_bulk_write(codec->control_data,
+					  data32 & 0xffffff,
+					  block_len / 2,
+					  (void *)(data + 8));
+
+			break;
+		default:
+			dev_warn(codec->dev, "%s: unknown block type %d\n",
+				 name, (data32 >> 24) & 0xff);
+			break;
+		}
+
+		/* Round up to the next 32 bit word */
+		block_len += block_len % 4;
+
+		data += block_len + 8;
+		len -= block_len + 8;
+	}
+
+	if (!check) {
+		dev_dbg(codec->dev, "%s: download done\n", name);
+		wm8994->cur_fw = fw;
+	} else {
+		dev_info(codec->dev, "%s: got firmware\n", name);
+	}
+
+	goto ok;
+
+err:
+	ret = -EINVAL;
+ok:
+	if (!check) {
+		snd_soc_write(codec, 0x900, 0x0);
+		snd_soc_write(codec, 0x102, 0x0);
+	}
+
+	return ret;
+}
+
+static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path)
+{
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_pdata *pdata = wm8994->pdata;
+	int i;
+
+	/* If the DSP is already running then noop */
+	if (snd_soc_read(codec, WM8958_DSP2_PROGRAM) & WM8958_DSP2_ENA)
+		return;
+
+	/* If we have MBC firmware download it */
+	if (wm8994->mbc)
+		wm8958_dsp2_fw(codec, "MBC", wm8994->mbc, false);
+
+	snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+			    WM8958_DSP2_ENA, WM8958_DSP2_ENA);
+
+	/* If we've got user supplied MBC settings use them */
+	if (pdata && pdata->num_mbc_cfgs) {
+		struct wm8958_mbc_cfg *cfg
+			= &pdata->mbc_cfgs[wm8994->mbc_cfg];
+
+		for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++)
+			snd_soc_write(codec, i + WM8958_MBC_BAND_1_K_1,
+				      cfg->coeff_regs[i]);
+
+		for (i = 0; i < ARRAY_SIZE(cfg->cutoff_regs); i++)
+			snd_soc_write(codec,
+				      i + WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1,
+				      cfg->cutoff_regs[i]);
+	}
+
+	/* Run the DSP */
+	snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
+		      WM8958_DSP2_RUNR);
+
+	/* And we're off! */
+	snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+			    WM8958_MBC_ENA |
+			    WM8958_MBC_SEL_MASK,
+			    path << WM8958_MBC_SEL_SHIFT |
+			    WM8958_MBC_ENA);
+}
+
+static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path)
+{
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_pdata *pdata = wm8994->pdata;
+	int i, ena;
+
+	if (wm8994->mbc_vss)
+		wm8958_dsp2_fw(codec, "MBC+VSS", wm8994->mbc_vss, false);
+
+	snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+			    WM8958_DSP2_ENA, WM8958_DSP2_ENA);
+
+	/* If we've got user supplied settings use them */
+	if (pdata && pdata->num_mbc_cfgs) {
+		struct wm8958_mbc_cfg *cfg
+			= &pdata->mbc_cfgs[wm8994->mbc_cfg];
+
+		for (i = 0; i < ARRAY_SIZE(cfg->combined_regs); i++)
+			snd_soc_write(codec, i + 0x2800,
+				      cfg->combined_regs[i]);
+	}
+
+	if (pdata && pdata->num_vss_cfgs) {
+		struct wm8958_vss_cfg *cfg
+			= &pdata->vss_cfgs[wm8994->vss_cfg];
+
+		for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
+			snd_soc_write(codec, i + 0x2600, cfg->regs[i]);
+	}
+
+	if (pdata && pdata->num_vss_hpf_cfgs) {
+		struct wm8958_vss_hpf_cfg *cfg
+			= &pdata->vss_hpf_cfgs[wm8994->vss_hpf_cfg];
+
+		for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
+			snd_soc_write(codec, i + 0x2400, cfg->regs[i]);
+	}
+
+	/* Run the DSP */
+	snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
+		      WM8958_DSP2_RUNR);
+
+	/* Enable the algorithms we've selected */
+	ena = 0;
+	if (wm8994->mbc_ena[path])
+		ena |= 0x8;
+	if (wm8994->hpf2_ena[path])
+		ena |= 0x4;
+	if (wm8994->hpf1_ena[path])
+		ena |= 0x2;
+	if (wm8994->vss_ena[path])
+		ena |= 0x1;
+
+	snd_soc_write(codec, 0x2201, ena);
+
+	/* Switch the DSP into the data path */
+	snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+			    WM8958_MBC_SEL_MASK | WM8958_MBC_ENA,
+			    path << WM8958_MBC_SEL_SHIFT | WM8958_MBC_ENA);
+}
+
+static void wm8958_dsp_start_enh_eq(struct snd_soc_codec *codec, int path)
+{
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_pdata *pdata = wm8994->pdata;
+	int i;
+
+	wm8958_dsp2_fw(codec, "ENH_EQ", wm8994->enh_eq, false);
+
+	snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+			    WM8958_DSP2_ENA, WM8958_DSP2_ENA);
+
+	/* If we've got user supplied settings use them */
+	if (pdata && pdata->num_enh_eq_cfgs) {
+		struct wm8958_enh_eq_cfg *cfg
+			= &pdata->enh_eq_cfgs[wm8994->enh_eq_cfg];
+
+		for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
+			snd_soc_write(codec, i + 0x2200,
+				      cfg->regs[i]);
+	}
+
+	/* Run the DSP */
+	snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
+		      WM8958_DSP2_RUNR);
+
+	/* Switch the DSP into the data path */
+	snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+			    WM8958_MBC_SEL_MASK | WM8958_MBC_ENA,
+			    path << WM8958_MBC_SEL_SHIFT | WM8958_MBC_ENA);
+}
+
+static void wm8958_dsp_apply(struct snd_soc_codec *codec, int path, int start)
+{
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	int pwr_reg = snd_soc_read(codec, WM8994_POWER_MANAGEMENT_5);
+	int ena, reg, aif;
+
+	switch (path) {
+	case 0:
+		pwr_reg &= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA);
+		aif = 0;
+		break;
+	case 1:
+		pwr_reg &= (WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA);
+		aif = 0;
+		break;
+	case 2:
+		pwr_reg &= (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA);
+		aif = 1;
+		break;
+	default:
+		BUG();
+		return;
+	}
+
+	/* Do we have both an active AIF and an active algorithm? */
+	ena = wm8994->mbc_ena[path] || wm8994->vss_ena[path] ||
+		wm8994->hpf1_ena[path] || wm8994->hpf2_ena[path] ||
+		wm8994->enh_eq_ena[path];
+	if (!pwr_reg)
+		ena = 0;
+
+	reg = snd_soc_read(codec, WM8958_DSP2_PROGRAM);
+
+	dev_dbg(codec->dev, "DSP path %d %d startup: %d, power: %x, DSP: %x\n",
+		path, wm8994->dsp_active, start, pwr_reg, reg);
+
+	if (start && ena) {
+		/* If the DSP is already running then noop */
+		if (reg & WM8958_DSP2_ENA)
+			return;
+
+		/* If either AIFnCLK is not yet enabled postpone */
+		if (!(snd_soc_read(codec, WM8994_AIF1_CLOCKING_1)
+		      & WM8994_AIF1CLK_ENA_MASK) &&
+		    !(snd_soc_read(codec, WM8994_AIF2_CLOCKING_1)
+		      & WM8994_AIF2CLK_ENA_MASK))
+			return;
+
+		/* Switch the clock over to the appropriate AIF */
+		snd_soc_update_bits(codec, WM8994_CLOCKING_1,
+				    WM8958_DSP2CLK_SRC | WM8958_DSP2CLK_ENA,
+				    aif << WM8958_DSP2CLK_SRC_SHIFT |
+				    WM8958_DSP2CLK_ENA);
+
+		if (wm8994->enh_eq_ena[path])
+			wm8958_dsp_start_enh_eq(codec, path);
+		else if (wm8994->vss_ena[path] || wm8994->hpf1_ena[path] ||
+		    wm8994->hpf2_ena[path])
+			wm8958_dsp_start_vss(codec, path);
+		else if (wm8994->mbc_ena[path])
+			wm8958_dsp_start_mbc(codec, path);
+
+		wm8994->dsp_active = path;
+
+		dev_dbg(codec->dev, "DSP running in path %d\n", path);
+	}
+
+	if (!start && wm8994->dsp_active == path) {
+		/* If the DSP is already stopped then noop */
+		if (!(reg & WM8958_DSP2_ENA))
+			return;
+
+		snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+				    WM8958_MBC_ENA, 0);	
+		snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
+			      WM8958_DSP2_STOP);
+		snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+				    WM8958_DSP2_ENA, 0);
+		snd_soc_update_bits(codec, WM8994_CLOCKING_1,
+				    WM8958_DSP2CLK_ENA, 0);
+
+		wm8994->dsp_active = -1;
+
+		dev_dbg(codec->dev, "DSP stopped\n");
+	}
+}
+
+int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
+		  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	int i;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+	case SND_SOC_DAPM_PRE_PMU:
+		for (i = 0; i < 3; i++)
+			wm8958_dsp_apply(codec, i, 1);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+	case SND_SOC_DAPM_PRE_PMD:
+		for (i = 0; i < 3; i++)
+			wm8958_dsp_apply(codec, i, 0);
+		break;
+	}
+
+	return 0;
+}
+
+/* Check if DSP2 is in use on another AIF */
+static int wm8958_dsp2_busy(struct wm8994_priv *wm8994, int aif)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wm8994->mbc_ena); i++) {
+		if (i == aif)
+			continue;
+		if (wm8994->mbc_ena[i] || wm8994->vss_ena[i] ||
+		    wm8994->hpf1_ena[i] || wm8994->hpf2_ena[i])
+			return 1;
+	}
+
+	return 0;
+}
+
+static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_pdata *pdata = wm8994->pdata;
+	int value = ucontrol->value.integer.value[0];
+	int reg;
+
+	/* Don't allow on the fly reconfiguration */
+	reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
+		return -EBUSY;
+
+	if (value >= pdata->num_mbc_cfgs)
+		return -EINVAL;
+
+	wm8994->mbc_cfg = value;
+
+	return 0;
+}
+
+static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg;
+
+	return 0;
+}
+
+static int wm8958_mbc_info(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int wm8958_mbc_get(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int mbc = kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc];
+
+	return 0;
+}
+
+static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int mbc = kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	if (wm8994->mbc_ena[mbc] == ucontrol->value.integer.value[0])
+		return 0;
+
+	if (ucontrol->value.integer.value[0] > 1)
+		return -EINVAL;
+
+	if (wm8958_dsp2_busy(wm8994, mbc)) {
+		dev_dbg(codec->dev, "DSP2 active on %d already\n", mbc);
+		return -EBUSY;
+	}
+
+	if (wm8994->enh_eq_ena[mbc])
+		return -EBUSY;
+
+	wm8994->mbc_ena[mbc] = ucontrol->value.integer.value[0];
+
+	wm8958_dsp_apply(codec, mbc, wm8994->mbc_ena[mbc]);
+
+	return 0;
+}
+
+#define WM8958_MBC_SWITCH(xname, xval) {\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+	.info = wm8958_mbc_info, \
+	.get = wm8958_mbc_get, .put = wm8958_mbc_put, \
+	.private_value = xval }
+
+static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_pdata *pdata = wm8994->pdata;
+	int value = ucontrol->value.integer.value[0];
+	int reg;
+
+	/* Don't allow on the fly reconfiguration */
+	reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
+		return -EBUSY;
+
+	if (value >= pdata->num_vss_cfgs)
+		return -EINVAL;
+
+	wm8994->vss_cfg = value;
+
+	return 0;
+}
+
+static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.enumerated.item[0] = wm8994->vss_cfg;
+
+	return 0;
+}
+
+static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_pdata *pdata = wm8994->pdata;
+	int value = ucontrol->value.integer.value[0];
+	int reg;
+
+	/* Don't allow on the fly reconfiguration */
+	reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
+		return -EBUSY;
+
+	if (value >= pdata->num_vss_hpf_cfgs)
+		return -EINVAL;
+
+	wm8994->vss_hpf_cfg = value;
+
+	return 0;
+}
+
+static int wm8958_get_vss_hpf_enum(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.enumerated.item[0] = wm8994->vss_hpf_cfg;
+
+	return 0;
+}
+
+static int wm8958_vss_info(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int wm8958_vss_get(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int vss = kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = wm8994->vss_ena[vss];
+
+	return 0;
+}
+
+static int wm8958_vss_put(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int vss = kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	if (wm8994->vss_ena[vss] == ucontrol->value.integer.value[0])
+		return 0;
+
+	if (ucontrol->value.integer.value[0] > 1)
+		return -EINVAL;
+
+	if (!wm8994->mbc_vss)
+		return -ENODEV;
+
+	if (wm8958_dsp2_busy(wm8994, vss)) {
+		dev_dbg(codec->dev, "DSP2 active on %d already\n", vss);
+		return -EBUSY;
+	}
+
+	if (wm8994->enh_eq_ena[vss])
+		return -EBUSY;
+
+	wm8994->vss_ena[vss] = ucontrol->value.integer.value[0];
+
+	wm8958_dsp_apply(codec, vss, wm8994->vss_ena[vss]);
+
+	return 0;
+}
+
+
+#define WM8958_VSS_SWITCH(xname, xval) {\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+	.info = wm8958_vss_info, \
+	.get = wm8958_vss_get, .put = wm8958_vss_put, \
+	.private_value = xval }
+
+static int wm8958_hpf_info(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int wm8958_hpf_get(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int hpf = kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	if (hpf < 3)
+		ucontrol->value.integer.value[0] = wm8994->hpf1_ena[hpf % 3];
+	else
+		ucontrol->value.integer.value[0] = wm8994->hpf2_ena[hpf % 3];
+
+	return 0;
+}
+
+static int wm8958_hpf_put(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int hpf = kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	if (hpf < 3) {
+		if (wm8994->hpf1_ena[hpf % 3] ==
+		    ucontrol->value.integer.value[0])
+			return 0;
+	} else {
+		if (wm8994->hpf2_ena[hpf % 3] ==
+		    ucontrol->value.integer.value[0])
+			return 0;
+	}
+
+	if (ucontrol->value.integer.value[0] > 1)
+		return -EINVAL;
+
+	if (!wm8994->mbc_vss)
+		return -ENODEV;
+
+	if (wm8958_dsp2_busy(wm8994, hpf % 3)) {
+		dev_dbg(codec->dev, "DSP2 active on %d already\n", hpf);
+		return -EBUSY;
+	}
+
+	if (wm8994->enh_eq_ena[hpf % 3])
+		return -EBUSY;
+
+	if (hpf < 3)
+		wm8994->hpf1_ena[hpf % 3] = ucontrol->value.integer.value[0];
+	else
+		wm8994->hpf2_ena[hpf % 3] = ucontrol->value.integer.value[0];
+
+	wm8958_dsp_apply(codec, hpf % 3, ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+#define WM8958_HPF_SWITCH(xname, xval) {\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+	.info = wm8958_hpf_info, \
+	.get = wm8958_hpf_get, .put = wm8958_hpf_put, \
+	.private_value = xval }
+
+static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_pdata *pdata = wm8994->pdata;
+	int value = ucontrol->value.integer.value[0];
+	int reg;
+
+	/* Don't allow on the fly reconfiguration */
+	reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
+		return -EBUSY;
+
+	if (value >= pdata->num_enh_eq_cfgs)
+		return -EINVAL;
+
+	wm8994->enh_eq_cfg = value;
+
+	return 0;
+}
+
+static int wm8958_get_enh_eq_enum(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.enumerated.item[0] = wm8994->enh_eq_cfg;
+
+	return 0;
+}
+
+static int wm8958_enh_eq_info(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int wm8958_enh_eq_get(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int eq = kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = wm8994->enh_eq_ena[eq];
+
+	return 0;
+}
+
+static int wm8958_enh_eq_put(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int eq = kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	if (wm8994->enh_eq_ena[eq] == ucontrol->value.integer.value[0])
+		return 0;
+
+	if (ucontrol->value.integer.value[0] > 1)
+		return -EINVAL;
+
+	if (!wm8994->enh_eq)
+		return -ENODEV;
+
+	if (wm8958_dsp2_busy(wm8994, eq)) {
+		dev_dbg(codec->dev, "DSP2 active on %d already\n", eq);
+		return -EBUSY;
+	}
+
+	if (wm8994->mbc_ena[eq] || wm8994->vss_ena[eq] ||
+	    wm8994->hpf1_ena[eq] || wm8994->hpf2_ena[eq])
+		return -EBUSY;
+
+	wm8994->enh_eq_ena[eq] = ucontrol->value.integer.value[0];
+
+	wm8958_dsp_apply(codec, eq, ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+#define WM8958_ENH_EQ_SWITCH(xname, xval) {\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+	.info = wm8958_enh_eq_info, \
+	.get = wm8958_enh_eq_get, .put = wm8958_enh_eq_put, \
+	.private_value = xval }
+
+static const struct snd_kcontrol_new wm8958_mbc_snd_controls[] = {
+WM8958_MBC_SWITCH("AIF1DAC1 MBC Switch", 0),
+WM8958_MBC_SWITCH("AIF1DAC2 MBC Switch", 1),
+WM8958_MBC_SWITCH("AIF2DAC MBC Switch", 2),
+};
+
+static const struct snd_kcontrol_new wm8958_vss_snd_controls[] = {
+WM8958_VSS_SWITCH("AIF1DAC1 VSS Switch", 0),
+WM8958_VSS_SWITCH("AIF1DAC2 VSS Switch", 1),
+WM8958_VSS_SWITCH("AIF2DAC VSS Switch", 2),
+WM8958_HPF_SWITCH("AIF1DAC1 HPF1 Switch", 0),
+WM8958_HPF_SWITCH("AIF1DAC2 HPF1 Switch", 1),
+WM8958_HPF_SWITCH("AIF2DAC HPF1 Switch", 2),
+WM8958_HPF_SWITCH("AIF1DAC1 HPF2 Switch", 3),
+WM8958_HPF_SWITCH("AIF1DAC2 HPF2 Switch", 4),
+WM8958_HPF_SWITCH("AIF2DAC HPF2 Switch", 5),
+};
+
+static const struct snd_kcontrol_new wm8958_enh_eq_snd_controls[] = {
+WM8958_ENH_EQ_SWITCH("AIF1DAC1 Enhanced EQ Switch", 0),
+WM8958_ENH_EQ_SWITCH("AIF1DAC2 Enhanced EQ Switch", 1),
+WM8958_ENH_EQ_SWITCH("AIF2DAC Enhanced EQ Switch", 2),
+};
+
+static void wm8958_enh_eq_loaded(const struct firmware *fw, void *context)
+{
+	struct snd_soc_codec *codec = context;
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	if (fw && (wm8958_dsp2_fw(codec, "ENH_EQ", fw, true) == 0)) {
+		mutex_lock(&codec->mutex);
+		wm8994->enh_eq = fw;
+		mutex_unlock(&codec->mutex);
+	}
+}
+
+static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context)
+{
+	struct snd_soc_codec *codec = context;
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	if (fw && (wm8958_dsp2_fw(codec, "MBC+VSS", fw, true) == 0)) {
+		mutex_lock(&codec->mutex);
+		wm8994->mbc_vss = fw;
+		mutex_unlock(&codec->mutex);
+	}
+
+	/* We can't have more than one request outstanding at once so
+	 * we daisy chain.
+	 */
+	request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+				"wm8958_enh_eq.wfw", codec->dev, GFP_KERNEL,
+				codec, wm8958_enh_eq_loaded);
+}
+
+static void wm8958_mbc_loaded(const struct firmware *fw, void *context)
+{
+	struct snd_soc_codec *codec = context;
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	if (wm8958_dsp2_fw(codec, "MBC", fw, true) != 0)
+		return;
+
+	mutex_lock(&codec->mutex);
+	wm8994->mbc = fw;
+	mutex_unlock(&codec->mutex);
+
+	/* We can't have more than one request outstanding at once so
+	 * we daisy chain.
+	 */
+	request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+				"wm8958_mbc_vss.wfw", codec->dev, GFP_KERNEL,
+				codec, wm8958_mbc_vss_loaded);
+}
+
+void wm8958_dsp2_init(struct snd_soc_codec *codec)
+{
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_pdata *pdata = wm8994->pdata;
+	int ret, i;
+
+	wm8994->dsp_active = -1;
+
+	snd_soc_add_controls(codec, wm8958_mbc_snd_controls,
+			     ARRAY_SIZE(wm8958_mbc_snd_controls));
+	snd_soc_add_controls(codec, wm8958_vss_snd_controls,
+			     ARRAY_SIZE(wm8958_vss_snd_controls));
+	snd_soc_add_controls(codec, wm8958_enh_eq_snd_controls,
+			     ARRAY_SIZE(wm8958_enh_eq_snd_controls));
+
+
+	/* We don't *require* firmware and don't want to delay boot */
+	request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+				"wm8958_mbc.wfw", codec->dev, GFP_KERNEL,
+				codec, wm8958_mbc_loaded);
+
+	if (!pdata)
+		return;
+
+	if (pdata->num_mbc_cfgs) {
+		struct snd_kcontrol_new control[] = {
+			SOC_ENUM_EXT("MBC Mode", wm8994->mbc_enum,
+				     wm8958_get_mbc_enum, wm8958_put_mbc_enum),
+		};
+
+		/* We need an array of texts for the enum API */
+		wm8994->mbc_texts = kmalloc(sizeof(char *)
+					    * pdata->num_mbc_cfgs, GFP_KERNEL);
+		if (!wm8994->mbc_texts) {
+			dev_err(wm8994->codec->dev,
+				"Failed to allocate %d MBC config texts\n",
+				pdata->num_mbc_cfgs);
+			return;
+		}
+
+		for (i = 0; i < pdata->num_mbc_cfgs; i++)
+			wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name;
+
+		wm8994->mbc_enum.max = pdata->num_mbc_cfgs;
+		wm8994->mbc_enum.texts = wm8994->mbc_texts;
+
+		ret = snd_soc_add_controls(wm8994->codec, control, 1);
+		if (ret != 0)
+			dev_err(wm8994->codec->dev,
+				"Failed to add MBC mode controls: %d\n", ret);
+	}
+
+	if (pdata->num_vss_cfgs) {
+		struct snd_kcontrol_new control[] = {
+			SOC_ENUM_EXT("VSS Mode", wm8994->vss_enum,
+				     wm8958_get_vss_enum, wm8958_put_vss_enum),
+		};
+
+		/* We need an array of texts for the enum API */
+		wm8994->vss_texts = kmalloc(sizeof(char *)
+					    * pdata->num_vss_cfgs, GFP_KERNEL);
+		if (!wm8994->vss_texts) {
+			dev_err(wm8994->codec->dev,
+				"Failed to allocate %d VSS config texts\n",
+				pdata->num_vss_cfgs);
+			return;
+		}
+
+		for (i = 0; i < pdata->num_vss_cfgs; i++)
+			wm8994->vss_texts[i] = pdata->vss_cfgs[i].name;
+
+		wm8994->vss_enum.max = pdata->num_vss_cfgs;
+		wm8994->vss_enum.texts = wm8994->vss_texts;
+
+		ret = snd_soc_add_controls(wm8994->codec, control, 1);
+		if (ret != 0)
+			dev_err(wm8994->codec->dev,
+				"Failed to add VSS mode controls: %d\n", ret);
+	}
+
+	if (pdata->num_vss_hpf_cfgs) {
+		struct snd_kcontrol_new control[] = {
+			SOC_ENUM_EXT("VSS HPF Mode", wm8994->vss_hpf_enum,
+				     wm8958_get_vss_hpf_enum,
+				     wm8958_put_vss_hpf_enum),
+		};
+
+		/* We need an array of texts for the enum API */
+		wm8994->vss_hpf_texts = kmalloc(sizeof(char *)
+						* pdata->num_vss_hpf_cfgs, GFP_KERNEL);
+		if (!wm8994->vss_hpf_texts) {
+			dev_err(wm8994->codec->dev,
+				"Failed to allocate %d VSS HPF config texts\n",
+				pdata->num_vss_hpf_cfgs);
+			return;
+		}
+
+		for (i = 0; i < pdata->num_vss_hpf_cfgs; i++)
+			wm8994->vss_hpf_texts[i] = pdata->vss_hpf_cfgs[i].name;
+
+		wm8994->vss_hpf_enum.max = pdata->num_vss_hpf_cfgs;
+		wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts;
+
+		ret = snd_soc_add_controls(wm8994->codec, control, 1);
+		if (ret != 0)
+			dev_err(wm8994->codec->dev,
+				"Failed to add VSS HPFmode controls: %d\n",
+				ret);
+	}
+
+	if (pdata->num_enh_eq_cfgs) {
+		struct snd_kcontrol_new control[] = {
+			SOC_ENUM_EXT("Enhanced EQ Mode", wm8994->enh_eq_enum,
+				     wm8958_get_enh_eq_enum,
+				     wm8958_put_enh_eq_enum),
+		};
+
+		/* We need an array of texts for the enum API */
+		wm8994->enh_eq_texts = kmalloc(sizeof(char *)
+						* pdata->num_enh_eq_cfgs, GFP_KERNEL);
+		if (!wm8994->enh_eq_texts) {
+			dev_err(wm8994->codec->dev,
+				"Failed to allocate %d enhanced EQ config texts\n",
+				pdata->num_enh_eq_cfgs);
+			return;
+		}
+
+		for (i = 0; i < pdata->num_enh_eq_cfgs; i++)
+			wm8994->enh_eq_texts[i] = pdata->enh_eq_cfgs[i].name;
+
+		wm8994->enh_eq_enum.max = pdata->num_enh_eq_cfgs;
+		wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts;
+
+		ret = snd_soc_add_controls(wm8994->codec, control, 1);
+		if (ret != 0)
+			dev_err(wm8994->codec->dev,
+				"Failed to add enhanced EQ controls: %d\n",
+				ret);
+	}
+}
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 500011eb8b2b..f90ae427242b 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -58,6 +58,7 @@ struct wm8962_priv {
 	int bclk;  /* Desired BCLK */
 	int lrclk;
 
+	struct completion fll_lock;
 	int fll_src;
 	int fll_fref;
 	int fll_fout;
@@ -2038,6 +2039,13 @@ static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
+static const char *cap_hpf_mode_text[] = {
+	"Hi-fi", "Application"
+};
+
+static const struct soc_enum cap_hpf_mode =
+	SOC_ENUM_SINGLE(WM8962_ADC_DAC_CONTROL_2, 10, 2, cap_hpf_mode_text);
+
 static const struct snd_kcontrol_new wm8962_snd_controls[] = {
 SOC_DOUBLE("Input Mixer Switch", WM8962_INPUT_MIXER_CONTROL_1, 3, 2, 1, 1),
 
@@ -2063,6 +2071,9 @@ SOC_DOUBLE_R("Capture Switch", WM8962_LEFT_INPUT_VOLUME,
 	     WM8962_RIGHT_INPUT_VOLUME, 7, 1, 1),
 SOC_DOUBLE_R("Capture ZC Switch", WM8962_LEFT_INPUT_VOLUME,
 	     WM8962_RIGHT_INPUT_VOLUME, 6, 1, 1),
+SOC_SINGLE("Capture HPF Switch", WM8962_ADC_DAC_CONTROL_1, 0, 1, 1),
+SOC_ENUM("Capture HPF Mode", cap_hpf_mode),
+SOC_SINGLE("Capture HPF Cutoff", WM8962_ADC_DAC_CONTROL_2, 7, 7, 0),
 
 SOC_DOUBLE_R_TLV("Sidetone Volume", WM8962_DAC_DSP_MIXING_1,
 		 WM8962_DAC_DSP_MIXING_2, 4, 12, 0, st_tlv),
@@ -2467,6 +2478,7 @@ SND_SOC_DAPM_INPUT("IN3R"),
 SND_SOC_DAPM_INPUT("IN4L"),
 SND_SOC_DAPM_INPUT("IN4R"),
 SND_SOC_DAPM_INPUT("Beep"),
+SND_SOC_DAPM_INPUT("DMICDAT"),
 
 SND_SOC_DAPM_MICBIAS("MICBIAS", WM8962_PWR_MGMT_1, 1, 0),
 
@@ -2486,6 +2498,8 @@ SND_SOC_DAPM_MIXER("MIXINL", WM8962_PWR_MGMT_1, 5, 0,
 SND_SOC_DAPM_MIXER("MIXINR", WM8962_PWR_MGMT_1, 4, 0,
 		   mixinr, ARRAY_SIZE(mixinr)),
 
+SND_SOC_DAPM_AIF_IN("DMIC", NULL, 0, WM8962_PWR_MGMT_1, 10, 0),
+
 SND_SOC_DAPM_ADC("ADCL", "Capture", WM8962_PWR_MGMT_1, 3, 0),
 SND_SOC_DAPM_ADC("ADCR", "Capture", WM8962_PWR_MGMT_1, 2, 0),
 
@@ -2563,13 +2577,17 @@ static const struct snd_soc_dapm_route wm8962_intercon[] = {
 
 	{ "MICBIAS", NULL, "SYSCLK" },
 
+	{ "DMIC", NULL, "DMICDAT" },
+
 	{ "ADCL", NULL, "SYSCLK" },
 	{ "ADCL", NULL, "TOCLK" },
 	{ "ADCL", NULL, "MIXINL" },
+	{ "ADCL", NULL, "DMIC" },
 
 	{ "ADCR", NULL, "SYSCLK" },
 	{ "ADCR", NULL, "TOCLK" },
 	{ "ADCR", NULL, "MIXINR" },
+	{ "ADCR", NULL, "DMIC" },
 
 	{ "STL", "Left", "ADCL" },
 	{ "STL", "Right", "ADCR" },
@@ -2990,7 +3008,6 @@ static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 	case WM8962_SYSCLK_FLL:
 		wm8962->sysclk = WM8962_SYSCLK_FLL;
 		src = 1 << WM8962_SYSCLK_SRC_SHIFT;
-		WARN_ON(freq != wm8962->fll_fout);
 		break;
 	default:
 		return -EINVAL;
@@ -3172,12 +3189,12 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
 	return 0;
 }
 
-static int wm8962_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
+static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 			  unsigned int Fref, unsigned int Fout)
 {
-	struct snd_soc_codec *codec = dai->codec;
 	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
 	struct _fll_div fll_div;
+	unsigned long timeout;
 	int ret;
 	int fll1 = snd_soc_read(codec, WM8962_FLL_CONTROL_1) & WM8962_FLL_ENA;
 
@@ -3244,6 +3261,11 @@ static int wm8962_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
 
 	dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
 
+	/* This should be a massive overestimate */
+	timeout = msecs_to_jiffies(1);
+
+	wait_for_completion_timeout(&wm8962->fll_lock, timeout);
+
 	wm8962->fll_fref = Fref;
 	wm8962->fll_fout = Fout;
 	wm8962->fll_src = source;
@@ -3274,7 +3296,6 @@ static struct snd_soc_dai_ops wm8962_dai_ops = {
 	.hw_params = wm8962_hw_params,
 	.set_sysclk = wm8962_set_dai_sysclk,
 	.set_fmt = wm8962_set_dai_fmt,
-	.set_pll = wm8962_set_fll,
 	.digital_mute = wm8962_mute,
 };
 
@@ -3340,6 +3361,11 @@ static irqreturn_t wm8962_irq(int irq, void *data)
 	active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2);
 	active &= ~mask;
 
+	if (active & WM8962_FLL_LOCK_EINT) {
+		dev_dbg(codec->dev, "FLL locked\n");
+		complete(&wm8962->fll_lock);
+	}
+
 	if (active & WM8962_FIFOS_ERR_EINT)
 		dev_err(codec->dev, "FIFO error\n");
 
@@ -3709,9 +3735,11 @@ static int wm8962_probe(struct snd_soc_codec *codec)
 					      dev);
 	u16 *reg_cache = codec->reg_cache;
 	int i, trigger, irq_pol;
+	bool dmicclk, dmicdat;
 
 	wm8962->codec = codec;
 	INIT_DELAYED_WORK(&wm8962->mic_work, wm8962_mic_work);
+	init_completion(&wm8962->fll_lock);
 
 	codec->cache_sync = 1;
 	codec->dapm.idle_bias_off = 1;
@@ -3845,6 +3873,29 @@ static int wm8962_probe(struct snd_soc_codec *codec)
 
 	wm8962_add_widgets(codec);
 
+	/* Save boards having to disable DMIC when not in use */
+	dmicclk = false;
+	dmicdat = false;
+	for (i = 0; i < WM8962_MAX_GPIO; i++) {
+		switch (snd_soc_read(codec, WM8962_GPIO_BASE + i)
+			& WM8962_GP2_FN_MASK) {
+		case WM8962_GPIO_FN_DMICCLK:
+			dmicclk = true;
+			break;
+		case WM8962_GPIO_FN_DMICDAT:
+			dmicdat = true;
+			break;
+		default:
+			break;
+		}
+	}
+	if (!dmicclk || !dmicdat) {
+		dev_dbg(codec->dev, "DMIC not in use, disabling\n");
+		snd_soc_dapm_nc_pin(&codec->dapm, "DMICDAT");
+	}
+	if (dmicclk != dmicdat)
+		dev_warn(codec->dev, "DMIC GPIOs partially configured\n");
+
 	wm8962_init_beep(codec);
 	wm8962_init_gpio(codec);
 
@@ -3868,9 +3919,10 @@ static int wm8962_probe(struct snd_soc_codec *codec)
 				i2c->irq, ret);
 			/* Non-fatal */
 		} else {
-			/* Enable error reporting IRQs by default */
+			/* Enable some IRQs by default */
 			snd_soc_update_bits(codec,
 					    WM8962_INTERRUPT_STATUS_2_MASK,
+					    WM8962_FLL_LOCK_EINT |
 					    WM8962_TEMP_SHUT_EINT |
 					    WM8962_FIFOS_ERR_EINT, 0);
 		}
@@ -3918,6 +3970,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8962 = {
 	.reg_cache_default = wm8962_reg,
 	.volatile_register = wm8962_volatile_register,
 	.readable_register = wm8962_readable_register,
+	.set_pll = wm8962_set_fll,
 };
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index 056aef904347..9e5ff789b805 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -718,7 +718,8 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w,
 static int class_w_put(struct snd_kcontrol *kcontrol,
 		       struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct snd_soc_codec *codec = widget->codec;
 	struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
 	int ret;
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 84e1bd1d2822..970a95c5360b 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -38,12 +38,6 @@
 #include "wm8994.h"
 #include "wm_hubs.h"
 
-struct fll_config {
-	int src;
-	int in;
-	int out;
-};
-
 #define WM8994_NUM_DRC 3
 #define WM8994_NUM_EQ  3
 
@@ -59,63 +53,11 @@ static int wm8994_retune_mobile_base[] = {
 	WM8994_AIF2_EQ_GAINS_1,
 };
 
-struct wm8994_micdet {
-	struct snd_soc_jack *jack;
-	int det;
-	int shrt;
-};
-
-/* codec private data */
-struct wm8994_priv {
-	struct wm_hubs_data hubs;
-	enum snd_soc_control_type control_type;
-	void *control_data;
-	struct snd_soc_codec *codec;
-	int sysclk[2];
-	int sysclk_rate[2];
-	int mclk[2];
-	int aifclk[2];
-	struct fll_config fll[2], fll_suspend[2];
-
-	int dac_rates[2];
-	int lrclk_shared[2];
-
-	int mbc_ena[3];
-
-	/* Platform dependent DRC configuration */
-	const char **drc_texts;
-	int drc_cfg[WM8994_NUM_DRC];
-	struct soc_enum drc_enum;
-
-	/* Platform dependent ReTune mobile configuration */
-	int num_retune_mobile_texts;
-	const char **retune_mobile_texts;
-	int retune_mobile_cfg[WM8994_NUM_EQ];
-	struct soc_enum retune_mobile_enum;
-
-	/* Platform dependent MBC configuration */
-	int mbc_cfg;
-	const char **mbc_texts;
-	struct soc_enum mbc_enum;
-
-	struct wm8994_micdet micdet[2];
-
-	wm8958_micdet_cb jack_cb;
-	void *jack_cb_data;
-	int micdet_irq;
-
-	int revision;
-	struct wm8994_pdata *pdata;
-
-	unsigned int aif1clk_enable:1;
-	unsigned int aif2clk_enable:1;
-
-	unsigned int aif1clk_disable:1;
-	unsigned int aif2clk_disable:1;
-};
-
 static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg)
 {
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994 *control = wm8994->control_data;
+
 	switch (reg) {
 	case WM8994_GPIO_1:
 	case WM8994_GPIO_2:
@@ -132,6 +74,15 @@ static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg)
 	case WM8994_INTERRUPT_STATUS_2:
 	case WM8994_INTERRUPT_RAW_STATUS_2:
 		return 1;
+
+	case WM8958_DSP2_PROGRAM:
+	case WM8958_DSP2_CONFIG:
+	case WM8958_DSP2_EXECCONTROL:
+		if (control->type == WM8958)
+			return 1;
+		else
+			return 0;
+
 	default:
 		break;
 	}
@@ -574,215 +525,6 @@ static const struct soc_enum dac_osr =
 static const struct soc_enum adc_osr =
 	SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 1, 2, osr_text);
 
-static void wm8958_mbc_apply(struct snd_soc_codec *codec, int mbc, int start)
-{
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-	struct wm8994_pdata *pdata = wm8994->pdata;
-	int pwr_reg = snd_soc_read(codec, WM8994_POWER_MANAGEMENT_5);
-	int ena, reg, aif, i;
-
-	switch (mbc) {
-	case 0:
-		pwr_reg &= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA);
-		aif = 0;
-		break;
-	case 1:
-		pwr_reg &= (WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA);
-		aif = 0;
-		break;
-	case 2:
-		pwr_reg &= (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA);
-		aif = 1;
-		break;
-	default:
-		BUG();
-		return;
-	}
-
-	/* We can only enable the MBC if the AIF is enabled and we
-	 * want it to be enabled. */
-	ena = pwr_reg && wm8994->mbc_ena[mbc];
-
-	reg = snd_soc_read(codec, WM8958_DSP2_PROGRAM);
-
-	dev_dbg(codec->dev, "MBC %d startup: %d, power: %x, DSP: %x\n",
-		mbc, start, pwr_reg, reg);
-
-	if (start && ena) {
-		/* If the DSP is already running then noop */
-		if (reg & WM8958_DSP2_ENA)
-			return;
-
-		/* Switch the clock over to the appropriate AIF */
-		snd_soc_update_bits(codec, WM8994_CLOCKING_1,
-				    WM8958_DSP2CLK_SRC | WM8958_DSP2CLK_ENA,
-				    aif << WM8958_DSP2CLK_SRC_SHIFT |
-				    WM8958_DSP2CLK_ENA);
-
-		snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
-				    WM8958_DSP2_ENA, WM8958_DSP2_ENA);
-
-		/* If we've got user supplied MBC settings use them */
-		if (pdata && pdata->num_mbc_cfgs) {
-			struct wm8958_mbc_cfg *cfg
-				= &pdata->mbc_cfgs[wm8994->mbc_cfg];
-
-			for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++)
-				snd_soc_write(codec, i + WM8958_MBC_BAND_1_K_1,
-					      cfg->coeff_regs[i]);
-
-			for (i = 0; i < ARRAY_SIZE(cfg->cutoff_regs); i++)
-				snd_soc_write(codec,
-					      i + WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1,
-					      cfg->cutoff_regs[i]);
-		}
-
-		/* Run the DSP */
-		snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
-			      WM8958_DSP2_RUNR);
-
-		/* And we're off! */
-		snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
-				    WM8958_MBC_ENA | WM8958_MBC_SEL_MASK,
-				    mbc << WM8958_MBC_SEL_SHIFT |
-				    WM8958_MBC_ENA);
-	} else {
-		/* If the DSP is already stopped then noop */
-		if (!(reg & WM8958_DSP2_ENA))
-			return;
-
-		snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
-				    WM8958_MBC_ENA, 0);	
-		snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
-				    WM8958_DSP2_ENA, 0);
-		snd_soc_update_bits(codec, WM8994_CLOCKING_1,
-				    WM8958_DSP2CLK_ENA, 0);
-	}
-}
-
-static int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
-		    struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = w->codec;
-	int mbc;
-
-	switch (w->shift) {
-	case 13:
-	case 12:
-		mbc = 2;
-		break;
-	case 11:
-	case 10:
-		mbc = 1;
-		break;
-	case 9:
-	case 8:
-		mbc = 0;
-		break;
-	default:
-		BUG();
-		return -EINVAL;
-	}
-
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		wm8958_mbc_apply(codec, mbc, 1);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		wm8958_mbc_apply(codec, mbc, 0);
-		break;
-	}
-
-	return 0;
-}
-
-static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
-			       struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-	struct wm8994_pdata *pdata = wm8994->pdata;
-	int value = ucontrol->value.integer.value[0];
-	int reg;
-
-	/* Don't allow on the fly reconfiguration */
-	reg = snd_soc_read(codec, WM8994_CLOCKING_1);
-	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
-		return -EBUSY;
-
-	if (value >= pdata->num_mbc_cfgs)
-		return -EINVAL;
-
-	wm8994->mbc_cfg = value;
-
-	return 0;
-}
-
-static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol,
-			       struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-
-	ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg;
-
-	return 0;
-}
-
-static int wm8958_mbc_info(struct snd_kcontrol *kcontrol,
-			   struct snd_ctl_elem_info *uinfo)
-{
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-	uinfo->count = 1;
-	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = 1;
-	return 0;
-}
-
-static int wm8958_mbc_get(struct snd_kcontrol *kcontrol,
-			  struct snd_ctl_elem_value *ucontrol)
-{
-	int mbc = kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-
-	ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc];
-
-	return 0;
-}
-
-static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
-			  struct snd_ctl_elem_value *ucontrol)
-{
-	int mbc = kcontrol->private_value;
-	int i;
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-
-	if (ucontrol->value.integer.value[0] > 1)
-		return -EINVAL;
-
-	for (i = 0; i < ARRAY_SIZE(wm8994->mbc_ena); i++) {
-		if (mbc != i && wm8994->mbc_ena[i]) {
-			dev_dbg(codec->dev, "MBC %d active already\n", mbc);
-			return -EBUSY;
-		}
-	}
-
-	wm8994->mbc_ena[mbc] = ucontrol->value.integer.value[0];
-
-	wm8958_mbc_apply(codec, mbc, wm8994->mbc_ena[mbc]);
-
-	return 0;
-}
-
-#define WM8958_MBC_SWITCH(xname, xval) {\
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
-	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
-	.info = wm8958_mbc_info, \
-	.get = wm8958_mbc_get, .put = wm8958_mbc_put, \
-	.private_value = xval }
-
 static const struct snd_kcontrol_new wm8994_snd_controls[] = {
 SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME,
 		 WM8994_AIF1_ADC1_RIGHT_VOLUME,
@@ -924,9 +666,6 @@ SOC_SINGLE_TLV("AIF2 EQ5 Volume", WM8994_AIF2_EQ_GAINS_2, 6, 31, 0,
 
 static const struct snd_kcontrol_new wm8958_snd_controls[] = {
 SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv),
-WM8958_MBC_SWITCH("AIF1DAC1 MBC Switch", 0),
-WM8958_MBC_SWITCH("AIF1DAC2 MBC Switch", 1),
-WM8958_MBC_SWITCH("AIF2DAC MBC Switch", 2),
 };
 
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
@@ -1032,6 +771,9 @@ static int late_enable_ev(struct snd_soc_dapm_widget *w,
 		break;
 	}
 
+	/* We may also have postponed startup of DSP, handle that. */
+	wm8958_aif_ev(w, kcontrol, event);
+
 	return 0;
 }
 
@@ -1135,7 +877,8 @@ static const char *hp_mux_text[] = {
 static int wm8994_put_hp_enum(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *w = wlist->widgets[0];
 	struct snd_soc_codec *codec = w->codec;
 	int ret;
 
@@ -1262,7 +1005,8 @@ SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
 static int wm8994_put_class_w(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *w = wlist->widgets[0];
 	struct snd_soc_codec *codec = w->codec;
 	int ret;
 
@@ -2180,6 +1924,8 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
 					    WM8994_VMID_BUF_ENA |
 					    WM8994_VMID_RAMP_MASK, 0);
 
+			wm8994->cur_fw = NULL;
+
 			pm_runtime_put(codec->dev);
 		}
 		break;
@@ -2672,11 +2418,22 @@ static struct snd_soc_dai_driver wm8994_dai[] = {
 static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994 *control = codec->control_data;
 	int i, ret;
 
+	switch (control->type) {
+	case WM8994:
+		snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, 0);
+		break;
+	case WM8958:
+		snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+				    WM8958_MICD_ENA, 0);
+		break;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
 		memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i],
-		       sizeof(struct fll_config));
+		       sizeof(struct wm8994_fll_config));
 		ret = _wm8994_set_fll(codec, i + 1, 0, 0, 0);
 		if (ret < 0)
 			dev_warn(codec->dev, "Failed to stop FLL%d: %d\n",
@@ -2691,6 +2448,7 @@ static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state)
 static int wm8994_resume(struct snd_soc_codec *codec)
 {
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994 *control = codec->control_data;
 	int i, ret;
 	unsigned int val, mask;
 
@@ -2729,6 +2487,19 @@ static int wm8994_resume(struct snd_soc_codec *codec)
 				 i + 1, ret);
 	}
 
+	switch (control->type) {
+	case WM8994:
+		if (wm8994->micdet[0].jack || wm8994->micdet[1].jack)
+			snd_soc_update_bits(codec, WM8994_MICBIAS,
+					    WM8994_MICD_ENA, WM8994_MICD_ENA);
+		break;
+	case WM8958:
+		if (wm8994->jack_cb)
+			snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+					    WM8958_MICD_ENA, WM8958_MICD_ENA);
+		break;
+	}
+
 	return 0;
 }
 #else
@@ -2862,34 +2633,6 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
 	dev_dbg(codec->dev, "%d ReTune Mobile configurations\n",
 		pdata->num_retune_mobile_cfgs);
 
-	if (pdata->num_mbc_cfgs) {
-		struct snd_kcontrol_new control[] = {
-			SOC_ENUM_EXT("MBC Mode", wm8994->mbc_enum,
-				     wm8958_get_mbc_enum, wm8958_put_mbc_enum),
-		};
-
-		/* We need an array of texts for the enum API */
-		wm8994->mbc_texts = kmalloc(sizeof(char *)
-					    * pdata->num_mbc_cfgs, GFP_KERNEL);
-		if (!wm8994->mbc_texts) {
-			dev_err(wm8994->codec->dev,
-				"Failed to allocate %d MBC config texts\n",
-				pdata->num_mbc_cfgs);
-			return;
-		}
-
-		for (i = 0; i < pdata->num_mbc_cfgs; i++)
-			wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name;
-
-		wm8994->mbc_enum.max = pdata->num_mbc_cfgs;
-		wm8994->mbc_enum.texts = wm8994->mbc_texts;
-
-		ret = snd_soc_add_controls(wm8994->codec, control, 1);
-		if (ret != 0)
-			dev_err(wm8994->codec->dev,
-				"Failed to add MBC mode controls: %d\n", ret);
-	}
-
 	if (pdata->num_retune_mobile_cfgs)
 		wm8994_handle_retune_mobile_pdata(wm8994);
 	else
@@ -3343,14 +3086,23 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 	case WM8958:
 		snd_soc_add_controls(codec, wm8958_snd_controls,
 				     ARRAY_SIZE(wm8958_snd_controls));
-		snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets,
-					  ARRAY_SIZE(wm8994_lateclk_widgets));
-		snd_soc_dapm_new_controls(dapm, wm8994_adc_widgets,
-					  ARRAY_SIZE(wm8994_adc_widgets));
-		snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets,
-					  ARRAY_SIZE(wm8994_dac_widgets));
 		snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
 					  ARRAY_SIZE(wm8958_dapm_widgets));
+		if (wm8994->revision < 1) {
+			snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets,
+						  ARRAY_SIZE(wm8994_lateclk_revd_widgets));
+			snd_soc_dapm_new_controls(dapm, wm8994_adc_revd_widgets,
+						  ARRAY_SIZE(wm8994_adc_revd_widgets));
+			snd_soc_dapm_new_controls(dapm, wm8994_dac_revd_widgets,
+						  ARRAY_SIZE(wm8994_dac_revd_widgets));
+		} else {
+			snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets,
+						  ARRAY_SIZE(wm8994_lateclk_widgets));
+			snd_soc_dapm_new_controls(dapm, wm8994_adc_widgets,
+						  ARRAY_SIZE(wm8994_adc_widgets));
+			snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets,
+						  ARRAY_SIZE(wm8994_dac_widgets));
+		}
 		break;
 	}
 		
@@ -3374,10 +3126,19 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 		}
 		break;
 	case WM8958:
-		snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon,
-					ARRAY_SIZE(wm8994_lateclk_intercon));
-		snd_soc_dapm_add_routes(dapm, wm8958_intercon,
-					ARRAY_SIZE(wm8958_intercon));
+		if (wm8994->revision < 1) {
+			snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon,
+						ARRAY_SIZE(wm8994_revd_intercon));
+			snd_soc_dapm_add_routes(dapm, wm8994_lateclk_revd_intercon,
+						ARRAY_SIZE(wm8994_lateclk_revd_intercon));
+		} else {
+			snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon,
+						ARRAY_SIZE(wm8994_lateclk_intercon));
+			snd_soc_dapm_add_routes(dapm, wm8958_intercon,
+						ARRAY_SIZE(wm8958_intercon));
+		}
+
+		wm8958_dsp2_init(codec);
 		break;
 	}
 
@@ -3420,6 +3181,12 @@ static int  wm8994_codec_remove(struct snd_soc_codec *codec)
 			free_irq(wm8994->micdet_irq, wm8994);
 		break;
 	}
+	if (wm8994->mbc)
+		release_firmware(wm8994->mbc);
+	if (wm8994->mbc_vss)
+		release_firmware(wm8994->mbc_vss);
+	if (wm8994->enh_eq)
+		release_firmware(wm8994->enh_eq);
 	kfree(wm8994->retune_mobile_texts);
 	kfree(wm8994->drc_texts);
 	kfree(wm8994);
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index 999b8851226b..0a1db04b73bd 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -10,6 +10,9 @@
 #define _WM8994_H
 
 #include <sound/soc.h>
+#include <linux/firmware.h>
+
+#include "wm_hubs.h"
 
 /* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */
 #define WM8994_SYSCLK_MCLK1 1
@@ -45,4 +48,98 @@ struct wm8994_access_mask {
 extern const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE];
 extern const u16 wm8994_reg_defaults[WM8994_CACHE_SIZE];
 
+int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
+		  struct snd_kcontrol *kcontrol, int event);
+
+void wm8958_dsp2_init(struct snd_soc_codec *codec);
+
+struct wm8994_micdet {
+	struct snd_soc_jack *jack;
+	int det;
+	int shrt;
+};
+
+/* codec private data */
+struct wm8994_fll_config {
+	int src;
+	int in;
+	int out;
+};
+
+#define WM8994_NUM_DRC 3
+#define WM8994_NUM_EQ  3
+
+struct wm8994_priv {
+	struct wm_hubs_data hubs;
+	enum snd_soc_control_type control_type;
+	void *control_data;
+	struct snd_soc_codec *codec;
+	int sysclk[2];
+	int sysclk_rate[2];
+	int mclk[2];
+	int aifclk[2];
+	struct wm8994_fll_config fll[2], fll_suspend[2];
+
+	int dac_rates[2];
+	int lrclk_shared[2];
+
+	int mbc_ena[3];
+	int hpf1_ena[3];
+	int hpf2_ena[3];
+	int vss_ena[3];
+	int enh_eq_ena[3];
+
+	/* Platform dependant DRC configuration */
+	const char **drc_texts;
+	int drc_cfg[WM8994_NUM_DRC];
+	struct soc_enum drc_enum;
+
+	/* Platform dependant ReTune mobile configuration */
+	int num_retune_mobile_texts;
+	const char **retune_mobile_texts;
+	int retune_mobile_cfg[WM8994_NUM_EQ];
+	struct soc_enum retune_mobile_enum;
+
+	/* Platform dependant MBC configuration */
+	int mbc_cfg;
+	const char **mbc_texts;
+	struct soc_enum mbc_enum;
+
+	/* Platform dependant VSS configuration */
+	int vss_cfg;
+	const char **vss_texts;
+	struct soc_enum vss_enum;
+
+	/* Platform dependant VSS HPF configuration */
+	int vss_hpf_cfg;
+	const char **vss_hpf_texts;
+	struct soc_enum vss_hpf_enum;
+
+	/* Platform dependant enhanced EQ configuration */
+	int enh_eq_cfg;
+	const char **enh_eq_texts;
+	struct soc_enum enh_eq_enum;
+
+	struct wm8994_micdet micdet[2];
+
+	wm8958_micdet_cb jack_cb;
+	void *jack_cb_data;
+	int micdet_irq;
+
+	int revision;
+	struct wm8994_pdata *pdata;
+
+	unsigned int aif1clk_enable:1;
+	unsigned int aif2clk_enable:1;
+
+	unsigned int aif1clk_disable:1;
+	unsigned int aif2clk_disable:1;
+
+	int dsp_active;
+	const struct firmware *cur_fw;
+	const struct firmware *mbc;
+	const struct firmware *mbc_vss;
+	const struct firmware *enh_eq;
+};
+
 #endif
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
index 67eaaecbb42e..5ad873fda814 100644
--- a/sound/soc/codecs/wm8995.c
+++ b/sound/soc/codecs/wm8995.c
@@ -305,11 +305,11 @@ static int check_clk_sys(struct snd_soc_dapm_widget *source,
 static int wm8995_put_class_w(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget *w;
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *w = wlist->widgets[0];
 	struct snd_soc_codec *codec;
 	int ret;
 
-	w = snd_kcontrol_chip(kcontrol);
 	codec = w->codec;
 	ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
 	wm8995_update_class_w(codec);
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
index 47b357adabdd..646b58dda849 100644
--- a/sound/soc/codecs/wm9705.c
+++ b/sound/soc/codecs/wm9705.c
@@ -142,7 +142,7 @@ static const struct snd_soc_dapm_widget wm9705_dapm_widgets[] = {
  * constantly enabled, we use the mutes on those inputs to simulate such
  * controls.
  */
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm9705_audio_map[] = {
 	/* HP mixer */
 	{"HP Mixer", "PCBeep Playback Switch", "PCBEEP PGA"},
 	{"HP Mixer", "CD Playback Switch", "CD PGA"},
@@ -200,17 +200,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	{"Right ADC", NULL, "ADC PGA"},
 };
 
-static int wm9705_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, wm9705_dapm_widgets,
-					ARRAY_SIZE(wm9705_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-	return 0;
-}
-
 /* We use a register cache to enhance read performance. */
 static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg)
 {
@@ -364,7 +353,6 @@ static int wm9705_soc_probe(struct snd_soc_codec *codec)
 
 	snd_soc_add_controls(codec, wm9705_snd_ac97_controls,
 				ARRAY_SIZE(wm9705_snd_ac97_controls));
-	wm9705_add_widgets(codec);
 
 	return 0;
 
@@ -390,6 +378,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9705 = {
 	.reg_word_size = sizeof(u16),
 	.reg_cache_step = 2,
 	.reg_cache_default = wm9705_reg,
+	.dapm_widgets = wm9705_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm9705_dapm_widgets),
+	.dapm_routes = wm9705_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(wm9705_audio_map),
 };
 
 static __devinit int wm9705_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index bf5d4ef1a2a6..90117f8156e8 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -332,7 +332,7 @@ SND_SOC_DAPM_INPUT("MIC1"),
 SND_SOC_DAPM_INPUT("MIC2"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm9712_audio_map[] = {
 	/* virtual mixer - mixes left & right channels for spk and mono */
 	{"AC97 Mixer", NULL, "Left DAC"},
 	{"AC97 Mixer", NULL, "Right DAC"},
@@ -429,17 +429,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	{"ROUT2", NULL, "Speaker PGA"},
 };
 
-static int wm9712_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, wm9712_dapm_widgets,
-				  ARRAY_SIZE(wm9712_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-	return 0;
-}
-
 static unsigned int ac97_read(struct snd_soc_codec *codec,
 	unsigned int reg)
 {
@@ -651,7 +640,6 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec)
 	wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	snd_soc_add_controls(codec, wm9712_snd_ac97_controls,
 				ARRAY_SIZE(wm9712_snd_ac97_controls));
-	wm9712_add_widgets(codec);
 
 	return 0;
 
@@ -678,6 +666,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9712 = {
 	.reg_word_size = sizeof(u16),
 	.reg_cache_step = 2,
 	.reg_cache_default = wm9712_reg,
+	.dapm_widgets = wm9712_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm9712_dapm_widgets),
+	.dapm_routes = wm9712_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(wm9712_audio_map),
 };
 
 static __devinit int wm9712_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 38ed98558718..7167cb6787db 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -487,7 +487,7 @@ SND_SOC_DAPM_INPUT("MIC2B"),
 SND_SOC_DAPM_VMID("VMID"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm9713_audio_map[] = {
 	/* left HP mixer */
 	{"Left HP Mixer", "Beep Playback Switch",    "PCBEEP"},
 	{"Left HP Mixer", "Voice Playback Switch",   "Voice DAC"},
@@ -644,18 +644,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	{"Capture Mono Mux", "Right", "Right Capture Source"},
 };
 
-static int wm9713_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, wm9713_dapm_widgets,
-				  ARRAY_SIZE(wm9713_dapm_widgets));
-
-	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-	return 0;
-}
-
 static unsigned int ac97_read(struct snd_soc_codec *codec,
 	unsigned int reg)
 {
@@ -1231,7 +1219,6 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec)
 
 	snd_soc_add_controls(codec, wm9713_snd_ac97_controls,
 				ARRAY_SIZE(wm9713_snd_ac97_controls));
-	wm9713_add_widgets(codec);
 
 	return 0;
 
@@ -1262,6 +1249,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9713 = {
 	.reg_word_size = sizeof(u16),
 	.reg_cache_step = 2,
 	.reg_cache_default = wm9713_reg,
+	.dapm_widgets = wm9713_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm9713_dapm_widgets),
+	.dapm_routes = wm9713_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(wm9713_audio_map),
 };
 
 static __devinit int wm9713_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index 4005e9af5d61..e55b298c14a0 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -787,17 +787,17 @@ static const struct snd_soc_dapm_route analogue_routes[] = {
 static const struct snd_soc_dapm_route lineout1_diff_routes[] = {
 	{ "LINEOUT1 Mixer", "IN1L Switch", "IN1L PGA" },
 	{ "LINEOUT1 Mixer", "IN1R Switch", "IN1R PGA" },
-	{ "LINEOUT1 Mixer", "Output Switch", "Left Output Mixer" },
+	{ "LINEOUT1 Mixer", "Output Switch", "Left Output PGA" },
 
 	{ "LINEOUT1N Driver", NULL, "LINEOUT1 Mixer" },
 	{ "LINEOUT1P Driver", NULL, "LINEOUT1 Mixer" },
 };
 
 static const struct snd_soc_dapm_route lineout1_se_routes[] = {
-	{ "LINEOUT1N Mixer", "Left Output Switch", "Left Output Mixer" },
-	{ "LINEOUT1N Mixer", "Right Output Switch", "Left Output Mixer" },
+	{ "LINEOUT1N Mixer", "Left Output Switch", "Left Output PGA" },
+	{ "LINEOUT1N Mixer", "Right Output Switch", "Right Output PGA" },
 
-	{ "LINEOUT1P Mixer", "Left Output Switch", "Left Output Mixer" },
+	{ "LINEOUT1P Mixer", "Left Output Switch", "Left Output PGA" },
 
 	{ "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" },
 	{ "LINEOUT1P Driver", NULL, "LINEOUT1P Mixer" },
@@ -806,17 +806,17 @@ static const struct snd_soc_dapm_route lineout1_se_routes[] = {
 static const struct snd_soc_dapm_route lineout2_diff_routes[] = {
 	{ "LINEOUT2 Mixer", "IN2L Switch", "IN2L PGA" },
 	{ "LINEOUT2 Mixer", "IN2R Switch", "IN2R PGA" },
-	{ "LINEOUT2 Mixer", "Output Switch", "Right Output Mixer" },
+	{ "LINEOUT2 Mixer", "Output Switch", "Right Output PGA" },
 
 	{ "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" },
 	{ "LINEOUT2P Driver", NULL, "LINEOUT2 Mixer" },
 };
 
 static const struct snd_soc_dapm_route lineout2_se_routes[] = {
-	{ "LINEOUT2N Mixer", "Left Output Switch", "Left Output Mixer" },
-	{ "LINEOUT2N Mixer", "Right Output Switch", "Left Output Mixer" },
+	{ "LINEOUT2N Mixer", "Left Output Switch", "Left Output PGA" },
+	{ "LINEOUT2N Mixer", "Right Output Switch", "Right Output PGA" },
 
-	{ "LINEOUT2P Mixer", "Right Output Switch", "Right Output Mixer" },
+	{ "LINEOUT2P Mixer", "Right Output Switch", "Right Output PGA" },
 
 	{ "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" },
 	{ "LINEOUT2P Driver", NULL, "LINEOUT2P Mixer" },
@@ -836,17 +836,21 @@ int wm_hubs_add_analogue_controls(struct snd_soc_codec *codec)
 	snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_3_4_VOLUME,
 			    WM8993_IN2_VU, WM8993_IN2_VU);
 
+	snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_LEFT,
+			    WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);
 	snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_RIGHT,
 			    WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);
 
 	snd_soc_update_bits(codec, WM8993_LEFT_OUTPUT_VOLUME,
-			    WM8993_HPOUT1L_ZC, WM8993_HPOUT1L_ZC);
+			    WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC,
+			    WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC);
 	snd_soc_update_bits(codec, WM8993_RIGHT_OUTPUT_VOLUME,
 			    WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC,
 			    WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC);
 
 	snd_soc_update_bits(codec, WM8993_LEFT_OPGA_VOLUME,
-			    WM8993_MIXOUTL_ZC, WM8993_MIXOUTL_ZC);
+			    WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU,
+			    WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU);
 	snd_soc_update_bits(codec, WM8993_RIGHT_OPGA_VOLUME,
 			    WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU,
 			    WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU);
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index 4ddc6d3b6678..8566238db2a5 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -909,6 +909,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 	dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
 	dma_data->asp_chan_q = pdata->asp_chan_q;
 	dma_data->ram_chan_q = pdata->ram_chan_q;
+	dma_data->sram_size = pdata->sram_size_playback;
 	dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset +
 							mem->start);
 
@@ -925,6 +926,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 	dma_data = &dev->dma_params[SNDRV_PCM_STREAM_CAPTURE];
 	dma_data->asp_chan_q = pdata->asp_chan_q;
 	dma_data->ram_chan_q = pdata->ram_chan_q;
+	dma_data->sram_size = pdata->sram_size_capture;
 	dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset +
 							mem->start);
 
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
index ac2ded969253..5b13feca7537 100644
--- a/sound/soc/imx/imx-ssi.c
+++ b/sound/soc/imx/imx-ssi.c
@@ -667,12 +667,6 @@ static int imx_ssi_probe(struct platform_device *pdev)
 	if (res)
 		ssi->dma_params_rx.dma = res->start;
 
-	if ((cpu_is_mx27() || cpu_is_mx21()) &&
-			!(ssi->flags & IMX_SSI_USE_AC97) &&
-			(ssi->flags & IMX_SSI_DMA)) {
-		ssi->flags |= IMX_SSI_DMA;
-	}
-
 	platform_set_drvdata(pdev, ssi);
 
 	ret = snd_soc_register_dai(&pdev->dev, dai);
diff --git a/sound/soc/jz4740/qi_lb60.c b/sound/soc/jz4740/qi_lb60.c
index 49723e3e7e38..c5fc339f68f1 100644
--- a/sound/soc/jz4740/qi_lb60.c
+++ b/sound/soc/jz4740/qi_lb60.c
@@ -27,11 +27,7 @@
 static int qi_lb60_spk_event(struct snd_soc_dapm_widget *widget,
 			     struct snd_kcontrol *ctrl, int event)
 {
-	int on = 0;
-	if (event & SND_SOC_DAPM_POST_PMU)
-		on = 1;
-	else if (event & SND_SOC_DAPM_PRE_PMD)
-		on = 0;
+	int on = !SND_SOC_DAPM_EVENT_OFF(event);
 
 	gpio_set_value(QI_LB60_SND_GPIO, on);
 	gpio_set_value(QI_LB60_AMP_GPIO, on);
@@ -70,12 +66,6 @@ static int qi_lb60_codec_init(struct snd_soc_pcm_runtime *rtd)
 		return ret;
 	}
 
-	snd_soc_dapm_new_controls(dapm, qi_lb60_widgets,
-				  ARRAY_SIZE(qi_lb60_widgets));
-	snd_soc_dapm_add_routes(dapm, qi_lb60_routes,
-				ARRAY_SIZE(qi_lb60_routes));
-	snd_soc_dapm_sync(dapm);
-
 	return 0;
 }
 
@@ -93,10 +83,20 @@ static struct snd_soc_card qi_lb60 = {
 	.name = "QI LB60",
 	.dai_link = &qi_lb60_dai,
 	.num_links = 1,
+
+	.dapm_widgets = qi_lb60_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(qi_lb60_widgets),
+	.dapm_routes = qi_lb60_routes,
+	.num_dapm_routes = ARRAY_SIZE(qi_lb60_routes),
 };
 
 static struct platform_device *qi_lb60_snd_device;
 
+static const struct gpio qi_lb60_gpios[] = {
+	{ QI_LB60_SND_GPIO, GPIOF_OUT_INIT_LOW, "SND" },
+	{ QI_LB60_AMP_GPIO, GPIOF_OUT_INIT_LOW, "AMP" },
+};
+
 static int __init qi_lb60_init(void)
 {
 	int ret;
@@ -106,23 +106,12 @@ static int __init qi_lb60_init(void)
 	if (!qi_lb60_snd_device)
 		return -ENOMEM;
 
-	ret = gpio_request(QI_LB60_SND_GPIO, "SND");
+	ret = gpio_request_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
 	if (ret) {
-		pr_err("qi_lb60 snd: Failed to request SND GPIO(%d): %d\n",
-				QI_LB60_SND_GPIO, ret);
+		pr_err("qi_lb60 snd: Failed to request gpios: %d\n", ret);
 		goto err_device_put;
 	}
 
-	ret = gpio_request(QI_LB60_AMP_GPIO, "AMP");
-	if (ret) {
-		pr_err("qi_lb60 snd: Failed to request AMP GPIO(%d): %d\n",
-				QI_LB60_AMP_GPIO, ret);
-		goto err_gpio_free_snd;
-	}
-
-	gpio_direction_output(QI_LB60_SND_GPIO, 0);
-	gpio_direction_output(QI_LB60_AMP_GPIO, 0);
-
 	platform_set_drvdata(qi_lb60_snd_device, &qi_lb60);
 
 	ret = platform_device_add(qi_lb60_snd_device);
@@ -135,10 +124,8 @@ static int __init qi_lb60_init(void)
 
 err_unset_pdata:
 	platform_set_drvdata(qi_lb60_snd_device, NULL);
-/*err_gpio_free_amp:*/
-	gpio_free(QI_LB60_AMP_GPIO);
-err_gpio_free_snd:
-	gpio_free(QI_LB60_SND_GPIO);
+/*err_gpio_free_array:*/
+	gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
 err_device_put:
 	platform_device_put(qi_lb60_snd_device);
 
@@ -148,9 +135,8 @@ module_init(qi_lb60_init);
 
 static void __exit qi_lb60_exit(void)
 {
-	gpio_free(QI_LB60_AMP_GPIO);
-	gpio_free(QI_LB60_SND_GPIO);
 	platform_device_unregister(qi_lb60_snd_device);
+	gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
 }
 module_exit(qi_lb60_exit);
 
diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c
index 6b1f9d3bf34e..5a946b4115a2 100644
--- a/sound/soc/mid-x86/sst_platform.c
+++ b/sound/soc/mid-x86/sst_platform.c
@@ -249,10 +249,13 @@ static int sst_platform_open(struct snd_pcm_substream *substream)
 		return -ENOMEM;
 	}
 	stream->sstdrv_ops->vendor_id = MSIC_VENDOR_ID;
+	stream->sstdrv_ops->module_name = SST_CARD_NAMES;
 	/* registering with SST driver to get access to SST APIs to use */
 	ret_val = register_sst_card(stream->sstdrv_ops);
 	if (ret_val) {
 		pr_err("sst: sst card registration failed\n");
+		kfree(stream->sstdrv_ops);
+		kfree(stream);
 		return ret_val;
 	}
 	runtime->private_data = stream;
@@ -270,6 +273,7 @@ static int sst_platform_close(struct snd_pcm_substream *substream)
 	str_id = stream->stream_info.str_id;
 	if (str_id)
 		ret_val = stream->sstdrv_ops->pcm_control->close(str_id);
+	unregister_sst_card(stream->sstdrv_ops);
 	kfree(stream->sstdrv_ops);
 	kfree(stream);
 	return ret_val;
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 2175f09e57b6..07b772357244 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -4,7 +4,7 @@
  * Copyright (C) 2008 Nokia Corporation
  *
  * Contact: Jarkko Nikula <jhnikula@gmail.com>
- *          Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *          Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -146,7 +146,7 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
 	 * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words)
 	 * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words)
 	 */
-	if (cpu_is_omap343x() || cpu_is_omap44xx()) {
+	if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
 		/*
 		* Rule for the buffer size. We should not allow
 		* smaller buffer than the FIFO size to avoid underruns
@@ -258,7 +258,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
 	default:
 		return -EINVAL;
 	}
-	if (cpu_is_omap343x()) {
+	if (cpu_is_omap34xx()) {
 		dma_data->set_threshold = omap_mcbsp_set_threshold;
 		/* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
 		if (omap_mcbsp_get_dma_op_mode(bus_id) ==
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h
index 37dc7211ed3f..9a7dedd6f5a9 100644
--- a/sound/soc/omap/omap-mcbsp.h
+++ b/sound/soc/omap/omap-mcbsp.h
@@ -4,7 +4,7 @@
  * Copyright (C) 2008 Nokia Corporation
  *
  * Contact: Jarkko Nikula <jhnikula@gmail.com>
- *          Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *          Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index 8caeb8d305c3..e6a6b991d05f 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -4,7 +4,7 @@
  * Copyright (C) 2008 Nokia Corporation
  *
  * Contact: Jarkko Nikula <jhnikula@gmail.com>
- *          Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *          Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -37,7 +37,8 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {
 				  SNDRV_PCM_INFO_MMAP_VALID |
 				  SNDRV_PCM_INFO_INTERLEAVED |
 				  SNDRV_PCM_INFO_PAUSE |
-				  SNDRV_PCM_INFO_RESUME,
+				  SNDRV_PCM_INFO_RESUME |
+				  SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
 	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
 				  SNDRV_PCM_FMTBIT_S32_LE,
 	.period_bytes_min	= 32,
@@ -195,7 +196,7 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream)
 	if ((cpu_is_omap1510()))
 		omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ |
 			      OMAP_DMA_LAST_IRQ | OMAP_DMA_BLOCK_IRQ);
-	else
+	else if (!substream->runtime->no_period_wakeup)
 		omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ);
 
 	if (!(cpu_class_is_omap1())) {
diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h
index fea0515331fb..a0ed1dbb52d6 100644
--- a/sound/soc/omap/omap-pcm.h
+++ b/sound/soc/omap/omap-pcm.h
@@ -4,7 +4,7 @@
  * Copyright (C) 2008 Nokia Corporation
  *
  * Contact: Jarkko Nikula <jhnikula@gmail.com>
- *          Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *          Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index d0986220eff9..0aae998b6540 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 - 2009 Nokia Corporation
  *
- * Contact: Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Contact: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *          Eduardo Valentin <eduardo.valentin@nokia.com>
  *          Jarkko Nikula <jhnikula@gmail.com>
  *
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index 580f48571303..33ebc46b45b5 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -155,6 +155,15 @@ config SND_SOC_RAUMFELD
 	help
 	  Say Y if you want to add support for SoC audio on Raumfeld devices
 
+config SND_PXA2XX_SOC_HX4700
+	tristate "SoC Audio support for HP iPAQ hx4700"
+	depends on SND_PXA2XX_SOC && MACH_H4700
+	select SND_PXA2XX_SOC_I2S
+	select SND_SOC_AK4641
+	help
+	  Say Y if you want to add support for SoC audio on the
+	  HP iPAQ hx4700.
+
 config SND_PXA2XX_SOC_MAGICIAN
 	tristate "SoC Audio support for HTC Magician"
 	depends on SND_PXA2XX_SOC && MACH_MAGICIAN
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile
index 07660165ec8d..af357623be9d 100644
--- a/sound/soc/pxa/Makefile
+++ b/sound/soc/pxa/Makefile
@@ -22,6 +22,7 @@ snd-soc-palm27x-objs := palm27x.o
 snd-soc-saarb-objs := saarb.o
 snd-soc-tavorevb3-objs := tavorevb3.o
 snd-soc-zylonite-objs := zylonite.o
+snd-soc-hx4700-objs := hx4700.o
 snd-soc-magician-objs := magician.o
 snd-soc-mioa701-objs := mioa701_wm9713.o
 snd-soc-z2-objs := z2.o
@@ -37,6 +38,7 @@ obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o
 obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o
 obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o
 obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o
+obj-$(CONFIG_SND_PXA2XX_SOC_HX4700) += snd-soc-hx4700.o
 obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o
 obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
 obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c
index 9027da466cae..28757fb9df31 100644
--- a/sound/soc/pxa/corgi.c
+++ b/sound/soc/pxa/corgi.c
@@ -310,7 +310,7 @@ static struct snd_soc_dai_link corgi_dai = {
 	.cpu_dai_name = "pxa2xx-i2s",
 	.codec_dai_name = "wm8731-hifi",
 	.platform_name = "pxa-pcm-audio",
-	.codec_name = "wm8731-codec.0-001b",
+	.codec_name = "wm8731.0-001b",
 	.init = corgi_wm8731_init,
 	.ops = &corgi_ops,
 };
diff --git a/sound/soc/pxa/hx4700.c b/sound/soc/pxa/hx4700.c
new file mode 100644
index 000000000000..65c124831a00
--- /dev/null
+++ b/sound/soc/pxa/hx4700.c
@@ -0,0 +1,255 @@
+/*
+ * SoC audio for HP iPAQ hx4700
+ *
+ * Copyright (c) 2009 Philipp Zabel
+ *
+ *  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/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <mach/hx4700.h>
+#include <asm/mach-types.h>
+#include "pxa2xx-i2s.h"
+
+#include "../codecs/ak4641.h"
+
+static struct snd_soc_jack hs_jack;
+
+/* Headphones jack detection DAPM pin */
+static struct snd_soc_jack_pin hs_jack_pin[] = {
+	{
+		.pin	= "Headphone Jack",
+		.mask	= SND_JACK_HEADPHONE,
+	},
+	{
+		.pin	= "Speaker",
+		/* disable speaker when hp jack is inserted */
+		.mask   = SND_JACK_HEADPHONE,
+		.invert	= 1,
+	},
+};
+
+/* Headphones jack detection GPIO */
+static struct snd_soc_jack_gpio hs_jack_gpio = {
+	.gpio		= GPIO75_HX4700_EARPHONE_nDET,
+	.invert		= true,
+	.name		= "hp-gpio",
+	.report		= SND_JACK_HEADPHONE,
+	.debounce_time	= 200,
+};
+
+/*
+ * iPAQ hx4700 uses I2S for capture and playback.
+ */
+static int hx4700_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->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+
+	/* set codec DAI configuration */
+	ret = snd_soc_dai_set_fmt(codec_dai,
+			SND_SOC_DAIFMT_MSB | 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_MSB | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set the I2S system clock as output */
+	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+			SND_SOC_CLOCK_OUT);
+	if (ret < 0)
+		return ret;
+
+	/* inform codec driver about clock freq *
+	 * (PXA I2S always uses divider 256)    */
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, 256 * params_rate(params),
+			SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops hx4700_ops = {
+	.hw_params = hx4700_hw_params,
+};
+
+static int hx4700_spk_power(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *k, int event)
+{
+	gpio_set_value(GPIO107_HX4700_SPK_nSD, !!SND_SOC_DAPM_EVENT_ON(event));
+	return 0;
+}
+
+static int hx4700_hp_power(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *k, int event)
+{
+	gpio_set_value(GPIO92_HX4700_HP_DRIVER, !!SND_SOC_DAPM_EVENT_ON(event));
+	return 0;
+}
+
+/* hx4700 machine dapm widgets */
+static const struct snd_soc_dapm_widget hx4700_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", hx4700_hp_power),
+	SND_SOC_DAPM_SPK("Speaker", hx4700_spk_power),
+	SND_SOC_DAPM_MIC("Built-in Microphone", NULL),
+};
+
+/* hx4700 machine audio_map */
+static const struct snd_soc_dapm_route hx4700_audio_map[] = {
+
+	/* Headphone connected to LOUT, ROUT */
+	{"Headphone Jack", NULL, "LOUT"},
+	{"Headphone Jack", NULL, "ROUT"},
+
+	/* Speaker connected to MOUT2 */
+	{"Speaker", NULL, "MOUT2"},
+
+	/* Microphone connected to MICIN */
+	{"MICIN", NULL, "Built-in Microphone"},
+	{"AIN", NULL, "MICOUT"},
+};
+
+/*
+ * Logic for a ak4641 as connected on a HP iPAQ hx4700
+ */
+static int hx4700_ak4641_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	int err;
+
+	/* NC codec pins */
+	/* FIXME: is anything connected here? */
+	snd_soc_dapm_nc_pin(dapm, "MOUT1");
+	snd_soc_dapm_nc_pin(dapm, "MICEXT");
+	snd_soc_dapm_nc_pin(dapm, "AUX");
+
+	/* Jack detection API stuff */
+	err = snd_soc_jack_new(codec, "Headphone Jack",
+				SND_JACK_HEADPHONE, &hs_jack);
+	if (err)
+		return err;
+
+	err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pin),
+					hs_jack_pin);
+	if (err)
+		return err;
+
+	err = snd_soc_jack_add_gpios(&hs_jack, 1, &hs_jack_gpio);
+
+	return err;
+}
+
+/* hx4700 digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link hx4700_dai = {
+	.name = "ak4641",
+	.stream_name = "AK4641",
+	.cpu_dai_name = "pxa2xx-i2s",
+	.codec_dai_name = "ak4641-hifi",
+	.platform_name = "pxa-pcm-audio",
+	.codec_name = "ak4641.0-0012",
+	.init = hx4700_ak4641_init,
+	.ops = &hx4700_ops,
+};
+
+/* hx4700 audio machine driver */
+static struct snd_soc_card snd_soc_card_hx4700 = {
+	.name			= "iPAQ hx4700",
+	.dai_link		= &hx4700_dai,
+	.num_links		= 1,
+	.dapm_widgets		= hx4700_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(hx4700_dapm_widgets),
+	.dapm_routes		= hx4700_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(hx4700_audio_map),
+};
+
+static struct gpio hx4700_audio_gpios[] = {
+	{ GPIO107_HX4700_SPK_nSD, GPIOF_OUT_INIT_HIGH, "SPK_POWER" },
+	{ GPIO92_HX4700_HP_DRIVER, GPIOF_OUT_INIT_LOW, "EP_POWER" },
+};
+
+static int __devinit hx4700_audio_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	if (!machine_is_h4700())
+		return -ENODEV;
+
+	ret = gpio_request_array(hx4700_audio_gpios,
+				ARRAY_SIZE(hx4700_audio_gpios));
+	if (ret)
+		return ret;
+
+	snd_soc_card_hx4700.dev = &pdev->dev;
+	ret = snd_soc_register_card(&snd_soc_card_hx4700);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int __devexit hx4700_audio_remove(struct platform_device *pdev)
+{
+	snd_soc_jack_free_gpios(&hs_jack, 1, &hs_jack_gpio);
+	snd_soc_unregister_card(&snd_soc_card_hx4700);
+
+	gpio_set_value(GPIO92_HX4700_HP_DRIVER, 0);
+	gpio_set_value(GPIO107_HX4700_SPK_nSD, 0);
+
+	gpio_free_array(hx4700_audio_gpios, ARRAY_SIZE(hx4700_audio_gpios));
+	return 0;
+}
+
+static struct platform_driver hx4700_audio_driver = {
+	.driver	= {
+		.name = "hx4700-audio",
+		.owner = THIS_MODULE,
+		.pm = &snd_soc_pm_ops,
+	},
+	.probe	= hx4700_audio_probe,
+	.remove	= __devexit_p(hx4700_audio_remove),
+};
+
+static int __init hx4700_modinit(void)
+{
+	return platform_driver_register(&hx4700_audio_driver);
+}
+module_init(hx4700_modinit);
+
+static void __exit hx4700_modexit(void)
+{
+	platform_driver_unregister(&hx4700_audio_driver);
+}
+
+module_exit(hx4700_modexit);
+
+MODULE_AUTHOR("Philipp Zabel");
+MODULE_DESCRIPTION("ALSA SoC iPAQ hx4700");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:hx4700-audio");
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index a7d4999f9b24..da3ae4316cf2 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -276,7 +276,7 @@ static struct snd_soc_dai_link poodle_dai = {
 	.cpu_dai_name = "pxa2xx-i2s",
 	.codec_dai_name = "wm8731-hifi",
 	.platform_name = "pxa-pcm-audio",
-	.codec_name = "wm8731-codec.0-001b",
+	.codec_name = "wm8731.0-001b",
 	.init = poodle_wm8731_init,
 	.ops = &poodle_ops,
 };
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
index 8e1571350630..b253d864868a 100644
--- a/sound/soc/pxa/spitz.c
+++ b/sound/soc/pxa/spitz.c
@@ -42,6 +42,7 @@
 
 static int spitz_jack_func;
 static int spitz_spk_func;
+static int spitz_mic_gpio;
 
 static void spitz_ext_control(struct snd_soc_codec *codec)
 {
@@ -217,14 +218,7 @@ static int spitz_set_spk(struct snd_kcontrol *kcontrol,
 static int spitz_mic_bias(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *k, int event)
 {
-	if (machine_is_borzoi() || machine_is_spitz())
-		gpio_set_value(SPITZ_GPIO_MIC_BIAS,
-				SND_SOC_DAPM_EVENT_ON(event));
-
-	if (machine_is_akita())
-		gpio_set_value(AKITA_GPIO_MIC_BIAS,
-				SND_SOC_DAPM_EVENT_ON(event));
-
+	gpio_set_value_cansleep(spitz_mic_gpio, SND_SOC_DAPM_EVENT_ON(event));
 	return 0;
 }
 
@@ -339,22 +333,45 @@ static int __init spitz_init(void)
 	if (!(machine_is_spitz() || machine_is_borzoi() || machine_is_akita()))
 		return -ENODEV;
 
+	if (machine_is_borzoi() || machine_is_spitz())
+		spitz_mic_gpio = SPITZ_GPIO_MIC_BIAS;
+	else
+		spitz_mic_gpio = AKITA_GPIO_MIC_BIAS;
+
+	ret = gpio_request(spitz_mic_gpio, "MIC GPIO");
+	if (ret)
+		goto err1;
+
+	ret = gpio_direction_output(spitz_mic_gpio, 0);
+	if (ret)
+		goto err2;
+
 	spitz_snd_device = platform_device_alloc("soc-audio", -1);
-	if (!spitz_snd_device)
-		return -ENOMEM;
+	if (!spitz_snd_device) {
+		ret = -ENOMEM;
+		goto err2;
+	}
 
 	platform_set_drvdata(spitz_snd_device, &snd_soc_spitz);
-	ret = platform_device_add(spitz_snd_device);
 
+	ret = platform_device_add(spitz_snd_device);
 	if (ret)
-		platform_device_put(spitz_snd_device);
+		goto err3;
+
+	return 0;
 
+err3:
+	platform_device_put(spitz_snd_device);
+err2:
+	gpio_free(spitz_mic_gpio);
+err1:
 	return ret;
 }
 
 static void __exit spitz_exit(void)
 {
 	platform_device_unregister(spitz_snd_device);
+	gpio_free(spitz_mic_gpio);
 }
 
 module_init(spitz_init);
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index a3fdfb631469..459566bfcd35 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -162,3 +162,18 @@ config SND_SOC_SAMSUNG_SMDK_SPDIF
 	select SND_SAMSUNG_SPDIF
 	help
 	  Say Y if you want to add support for SoC S/PDIF audio on the SMDK.
+
+config SND_SOC_SMDK_WM8580_PCM
+	tristate "SoC PCM Audio support for WM8580 on SMDK"
+	depends on SND_SOC_SAMSUNG && (MACH_SMDK6450 || MACH_SMDKV210 || MACH_SMDKC110)
+	select SND_SOC_WM8580
+	select SND_SAMSUNG_PCM
+	help
+	  Say Y if you want to add support for SoC audio on the SMDK.
+
+config SND_SOC_SPEYSIDE
+	tristate "Audio support for Wolfson Speyside"
+	depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
+	select SND_SAMSUNG_I2S
+	select SND_SOC_WM8915
+	select SND_SOC_WM9081
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile
index 294dec05c26d..683843a2744f 100644
--- a/sound/soc/samsung/Makefile
+++ b/sound/soc/samsung/Makefile
@@ -34,6 +34,8 @@ snd-soc-smdk-wm9713-objs := smdk_wm9713.o
 snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
 snd-soc-goni-wm8994-objs := goni_wm8994.o
 snd-soc-smdk-spdif-objs := smdk_spdif.o
+snd-soc-smdk-wm8580pcm-objs := smdk_wm8580pcm.o
+snd-soc-speyside-objs := speyside.o
 
 obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
@@ -51,3 +53,5 @@ obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM9713) += snd-soc-smdk-wm9713.o
 obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o
 obj-$(CONFIG_SND_SOC_GONI_AQUILA_WM8994) += snd-soc-goni-wm8994.o
+obj-$(CONFIG_SND_SOC_SMDK_WM8580_PCM) += snd-soc-smdk-wm8580pcm.o
+obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o
diff --git a/sound/soc/samsung/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c
index 0e80daee8b6f..eb6d72ed55a7 100644
--- a/sound/soc/samsung/goni_wm8994.c
+++ b/sound/soc/samsung/goni_wm8994.c
@@ -246,7 +246,6 @@ static struct snd_soc_dai_link goni_dai[] = {
 	.stream_name = "Voice",
 	.cpu_dai_name = "goni-voice-dai",
 	.codec_dai_name = "wm8994-aif2",
-	.platform_name = "samsung-audio",
 	.codec_name = "wm8994-codec.0-001a",
 	.ops = &goni_voice_ops,
 },
diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c
index 452230975632..16152ed08648 100644
--- a/sound/soc/samsung/neo1973_wm8753.c
+++ b/sound/soc/samsung/neo1973_wm8753.c
@@ -432,7 +432,6 @@ static struct snd_soc_dai_link neo1973_dai[] = {
 { /* Voice via BT */
 	.name = "Bluetooth",
 	.stream_name = "Voice",
-	.platform_name = "samsung-audio",
 	.cpu_dai_name = "dfbmcs320-pcm",
 	.codec_dai_name = "wm8753-voice",
 	.codec_name = "wm8753-codec.0-001a",
diff --git a/sound/soc/samsung/smdk_wm8580pcm.c b/sound/soc/samsung/smdk_wm8580pcm.c
new file mode 100644
index 000000000000..0d12092df164
--- /dev/null
+++ b/sound/soc/samsung/smdk_wm8580pcm.c
@@ -0,0 +1,206 @@
+/*
+ *  sound/soc/samsung/smdk_wm8580pcm.c
+ *
+ *  Copyright (c) 2011 Samsung Electronics Co. Ltd
+ *
+ *  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 <sound/soc.h>
+#include <sound/pcm_params.h>
+#include <sound/pcm.h>
+
+#include <asm/mach-types.h>
+
+#include "../codecs/wm8580.h"
+#include "dma.h"
+#include "pcm.h"
+
+/*
+ * Board Settings:
+ *  o '1' means 'ON'
+ *  o '0' means 'OFF'
+ *  o 'X' means 'Don't care'
+ *
+ * SMDK6410, SMDK6440, SMDK6450 Base B/D: CFG1-0000, CFG2-1111
+ * SMDKC110, SMDKV210: CFGB11-100100, CFGB12-0000
+ */
+
+#define SMDK_WM8580_EXT_OSC 12000000
+#define SMDK_WM8580_EXT_MCLK 4096000
+#define SMDK_WM8580_EXT_VOICE 2048000
+
+static unsigned long mclk_freq;
+static unsigned long xtal_freq;
+
+/*
+ * If MCLK clock directly gets from XTAL, we don't have to use PLL
+ * to make MCLK, but if XTAL clock source connects with other codec
+ * pin (like XTI), we should have to set codec's PLL to make MCLK.
+ * Because Samsung SoC does not support pcmcdclk output like I2S.
+ */
+
+static int smdk_wm8580_pcm_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->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int rfs, ret;
+
+	switch (params_rate(params)) {
+	case 8000:
+		break;
+	default:
+		printk(KERN_ERR "%s:%d Sampling Rate %u not supported!\n",
+		__func__, __LINE__, params_rate(params));
+		return -EINVAL;
+	}
+
+	rfs = mclk_freq / params_rate(params) / 2;
+
+	/* Set the codec DAI configuration */
+	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B
+				| SND_SOC_DAIFMT_IB_NF
+				| SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* Set the cpu DAI configuration */
+	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_B
+				| SND_SOC_DAIFMT_IB_NF
+				| SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	if (mclk_freq == xtal_freq) {
+		ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_MCLK,
+						mclk_freq, SND_SOC_CLOCK_IN);
+		if (ret < 0)
+			return ret;
+
+		ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
+						WM8580_CLKSRC_MCLK);
+		if (ret < 0)
+			return ret;
+	} else {
+		ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA,
+						mclk_freq, SND_SOC_CLOCK_IN);
+		if (ret < 0)
+			return ret;
+
+		ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
+						WM8580_CLKSRC_PLLA);
+		if (ret < 0)
+			return ret;
+
+		ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
+						xtal_freq, mclk_freq);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* Set PCM source clock on CPU */
+	ret = snd_soc_dai_set_sysclk(cpu_dai, S3C_PCM_CLKSRC_MUX,
+					mclk_freq, SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* Set SCLK_DIV for making bclk */
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_PCM_SCLK_PER_FS, rfs);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops smdk_wm8580_pcm_ops = {
+	.hw_params = smdk_wm8580_pcm_hw_params,
+};
+
+static struct snd_soc_dai_link smdk_dai[] = {
+	{
+		.name = "WM8580 PAIF PCM RX",
+		.stream_name = "Playback",
+		.cpu_dai_name = "samsung-pcm.0",
+		.codec_dai_name = "wm8580-hifi-playback",
+		.platform_name = "samsung-audio",
+		.codec_name = "wm8580-codec.0-001b",
+		.ops = &smdk_wm8580_pcm_ops,
+	}, {
+		.name = "WM8580 PAIF PCM TX",
+		.stream_name = "Capture",
+		.cpu_dai_name = "samsung-pcm.0",
+		.codec_dai_name = "wm8580-hifi-capture",
+		.platform_name = "samsung-audio",
+		.codec_name = "wm8580-codec.0-001b",
+		.ops = &smdk_wm8580_pcm_ops,
+	},
+};
+
+static struct snd_soc_card smdk_pcm = {
+	.name = "SMDK-PCM",
+	.dai_link = smdk_dai,
+	.num_links = 2,
+};
+
+/*
+ * After SMDKC110 Base Board's Rev is '0.1', 12MHz External OSC(X1)
+ * is absent (or not connected), so we connect EXT_VOICE_CLK(OSC4),
+ * 2.0484Mhz, directly with MCLK both Codec and SoC.
+ */
+static int __devinit snd_smdk_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+
+	xtal_freq = SMDK_WM8580_EXT_OSC;
+	mclk_freq = SMDK_WM8580_EXT_MCLK;
+
+	if (machine_is_smdkc110() || machine_is_smdkv210())
+		xtal_freq = mclk_freq = SMDK_WM8580_EXT_VOICE;
+
+	smdk_pcm.dev = &pdev->dev;
+	ret = snd_soc_register_card(&smdk_pcm);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __devexit snd_smdk_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_card(&smdk_pcm);
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static struct platform_driver snd_smdk_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "samsung-smdk-pcm",
+	},
+	.probe = snd_smdk_probe,
+	.remove = __devexit_p(snd_smdk_remove),
+};
+
+static int __init smdk_audio_init(void)
+{
+	return platform_driver_register(&snd_smdk_driver);
+}
+
+module_init(smdk_audio_init);
+
+static void __exit smdk_audio_exit(void)
+{
+	platform_driver_unregister(&snd_smdk_driver);
+}
+
+module_exit(smdk_audio_exit);
+
+MODULE_AUTHOR("Sangbeom Kim, <sbkim73@samsung.com>");
+MODULE_DESCRIPTION("ALSA SoC SMDK WM8580 for PCM");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c
new file mode 100644
index 000000000000..360a333cb7c0
--- /dev/null
+++ b/sound/soc/samsung/speyside.c
@@ -0,0 +1,332 @@
+/*
+ * Speyside audio support
+ *
+ * Copyright 2011 Wolfson Microelectronics
+ *
+ * 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 <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <linux/gpio.h>
+
+#include "../codecs/wm8915.h"
+#include "../codecs/wm9081.h"
+
+#define WM8915_HPSEL_GPIO 214
+
+static int speyside_set_bias_level(struct snd_soc_card *card,
+				   enum snd_soc_bias_level level)
+{
+	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_STANDBY:
+		ret = snd_soc_dai_set_sysclk(codec_dai, WM8915_SYSCLK_MCLK1,
+					     32768, SND_SOC_CLOCK_IN);
+		if (ret < 0)
+			return ret;
+
+		ret = snd_soc_dai_set_pll(codec_dai, WM8915_FLL_MCLK1,
+					  0, 0, 0);
+		if (ret < 0) {
+			pr_err("Failed to stop FLL\n");
+			return ret;
+		}
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int speyside_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->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	int ret;
+
+	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;
+
+	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;
+
+	ret = snd_soc_dai_set_pll(codec_dai, 0, WM8915_FLL_MCLK1,
+				  32768, 256 * 48000);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, WM8915_SYSCLK_FLL,
+				     256 * 48000, SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops speyside_ops = {
+	.hw_params = speyside_hw_params,
+};
+
+static struct snd_soc_jack speyside_headset;
+
+/* Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin speyside_headset_pins[] = {
+	{
+		.pin = "Headset Mic",
+		.mask = SND_JACK_MICROPHONE,
+	},
+	{
+		.pin = "Headphone",
+		.mask = SND_JACK_HEADPHONE,
+	},
+};
+
+/* Default the headphone selection to active high */
+static int speyside_jack_polarity;
+
+static int speyside_get_micbias(struct snd_soc_dapm_widget *source,
+				struct snd_soc_dapm_widget *sink)
+{
+	if (speyside_jack_polarity && (strcmp(source->name, "MICB1") == 0))
+		return 1;
+	if (!speyside_jack_polarity && (strcmp(source->name, "MICB2") == 0))
+		return 1;
+
+	return 0;
+}
+
+static void speyside_set_polarity(struct snd_soc_codec *codec,
+				  int polarity)
+{
+	speyside_jack_polarity = !polarity;
+	gpio_direction_output(WM8915_HPSEL_GPIO, speyside_jack_polarity);
+
+	/* Re-run DAPM to make sure we're using the correct mic bias */
+	snd_soc_dapm_sync(&codec->dapm);
+}
+
+static int speyside_wm8915_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_dai *dai = rtd->codec_dai;
+	struct snd_soc_codec *codec = rtd->codec;
+	int ret;
+
+	ret = snd_soc_dai_set_sysclk(dai, WM8915_SYSCLK_MCLK1, 32768, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = gpio_request(WM8915_HPSEL_GPIO, "HP_SEL");
+	if (ret != 0)
+		pr_err("Failed to request HP_SEL GPIO: %d\n", ret);
+	gpio_direction_output(WM8915_HPSEL_GPIO, speyside_jack_polarity);
+
+	ret = snd_soc_jack_new(codec, "Headset",
+			       SND_JACK_HEADSET | SND_JACK_BTN_0,
+			       &speyside_headset);
+	if (ret)
+		return ret;
+
+	ret = snd_soc_jack_add_pins(&speyside_headset,
+				    ARRAY_SIZE(speyside_headset_pins),
+				    speyside_headset_pins);
+	if (ret)
+		return ret;
+
+	wm8915_detect(codec, &speyside_headset, speyside_set_polarity);
+
+	return 0;
+}
+
+static int speyside_late_probe(struct snd_soc_card *card)
+{
+	snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
+	snd_soc_dapm_ignore_suspend(&card->dapm, "Headset Mic");
+	snd_soc_dapm_ignore_suspend(&card->dapm, "Main AMIC");
+	snd_soc_dapm_ignore_suspend(&card->dapm, "Main DMIC");
+	snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
+	snd_soc_dapm_ignore_suspend(&card->dapm, "WM1250 Output");
+	snd_soc_dapm_ignore_suspend(&card->dapm, "WM1250 Input");
+
+	return 0;
+}
+
+static struct snd_soc_dai_link speyside_dai[] = {
+	{
+		.name = "CPU",
+		.stream_name = "CPU",
+		.cpu_dai_name = "samsung-i2s.0",
+		.codec_dai_name = "wm8915-aif1",
+		.platform_name = "samsung-audio",
+		.codec_name = "wm8915.1-001a",
+		.init = speyside_wm8915_init,
+		.ops = &speyside_ops,
+	},
+	{
+		.name = "Baseband",
+		.stream_name = "Baseband",
+		.cpu_dai_name = "wm8915-aif2",
+		.codec_dai_name = "wm1250-ev1",
+		.codec_name = "wm1250-ev1.1-0027",
+		.ops = &speyside_ops,
+		.ignore_suspend = 1,
+	},
+};
+
+static int speyside_wm9081_init(struct snd_soc_dapm_context *dapm)
+{
+	snd_soc_dapm_nc_pin(dapm, "LINEOUT");
+
+	/* At any time the WM9081 is active it will have this clock */
+	return snd_soc_codec_set_sysclk(dapm->codec, WM9081_SYSCLK_MCLK,
+					48000 * 256, 0);
+}
+
+static struct snd_soc_aux_dev speyside_aux_dev[] = {
+	{
+		.name = "wm9081",
+		.codec_name = "wm9081.1-006c",
+		.init = speyside_wm9081_init,
+	},
+};
+
+static struct snd_soc_codec_conf speyside_codec_conf[] = {
+	{
+		.dev_name = "wm9081.1-006c",
+		.name_prefix = "Sub",
+	},
+};
+
+static const struct snd_kcontrol_new controls[] = {
+	SOC_DAPM_PIN_SWITCH("Main Speaker"),
+	SOC_DAPM_PIN_SWITCH("Main DMIC"),
+	SOC_DAPM_PIN_SWITCH("Main AMIC"),
+	SOC_DAPM_PIN_SWITCH("WM1250 Input"),
+	SOC_DAPM_PIN_SWITCH("WM1250 Output"),
+};
+
+static struct snd_soc_dapm_widget widgets[] = {
+	SND_SOC_DAPM_HP("Headphone", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+
+	SND_SOC_DAPM_SPK("Main Speaker", NULL),
+
+	SND_SOC_DAPM_MIC("Main AMIC", NULL),
+	SND_SOC_DAPM_MIC("Main DMIC", NULL),
+};
+
+static struct snd_soc_dapm_route audio_paths[] = {
+	{ "IN1RN", NULL, "MICB1" },
+	{ "IN1RP", NULL, "MICB1" },
+	{ "IN1RN", NULL, "MICB2" },
+	{ "IN1RP", NULL, "MICB2" },
+	{ "MICB1", NULL, "Headset Mic", speyside_get_micbias },
+	{ "MICB2", NULL, "Headset Mic", speyside_get_micbias },
+
+	{ "IN1LP", NULL, "MICB2" },
+	{ "IN1RN", NULL, "MICB1" },
+	{ "MICB2", NULL, "Main AMIC" },
+
+	{ "DMIC1DAT", NULL, "MICB1" },
+	{ "DMIC2DAT", NULL, "MICB1" },
+	{ "MICB1", NULL, "Main DMIC" },
+
+	{ "Headphone", NULL, "HPOUT1L" },
+	{ "Headphone", NULL, "HPOUT1R" },
+
+	{ "Sub IN1", NULL, "HPOUT2L" },
+	{ "Sub IN2", NULL, "HPOUT2R" },
+
+	{ "Main Speaker", NULL, "Sub SPKN" },
+	{ "Main Speaker", NULL, "Sub SPKP" },
+	{ "Main Speaker", NULL, "SPKDAT" },
+};
+
+static struct snd_soc_card speyside = {
+	.name = "Speyside",
+	.dai_link = speyside_dai,
+	.num_links = ARRAY_SIZE(speyside_dai),
+	.aux_dev = speyside_aux_dev,
+	.num_aux_devs = ARRAY_SIZE(speyside_aux_dev),
+	.codec_conf = speyside_codec_conf,
+	.num_configs = ARRAY_SIZE(speyside_codec_conf),
+
+	.set_bias_level = speyside_set_bias_level,
+
+	.controls = controls,
+	.num_controls = ARRAY_SIZE(controls),
+	.dapm_widgets = widgets,
+	.num_dapm_widgets = ARRAY_SIZE(widgets),
+	.dapm_routes = audio_paths,
+	.num_dapm_routes = ARRAY_SIZE(audio_paths),
+
+	.late_probe = speyside_late_probe,
+};
+
+static __devinit int speyside_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &speyside;
+	int ret;
+
+	card->dev = &pdev->dev;
+
+	ret = snd_soc_register_card(card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+			ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __devexit speyside_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+	snd_soc_unregister_card(card);
+
+	return 0;
+}
+
+static struct platform_driver speyside_driver = {
+	.driver = {
+		.name = "speyside",
+		.owner = THIS_MODULE,
+		.pm = &snd_soc_pm_ops,
+	},
+	.probe = speyside_probe,
+	.remove = __devexit_p(speyside_remove),
+};
+
+static int __init speyside_audio_init(void)
+{
+	return platform_driver_register(&speyside_driver);
+}
+module_init(speyside_audio_init);
+
+static void __exit speyside_audio_exit(void)
+{
+	platform_driver_unregister(&speyside_driver);
+}
+module_exit(speyside_audio_exit);
+
+MODULE_DESCRIPTION("Speyside audio support");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:speyside");
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 23c0e83d4c19..4a9da6b5f4e1 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -86,8 +86,8 @@
 #define SE	(1 << 0)	/* Fix the master clock */
 
 /* CLK_RST */
-#define B_CLK		0x00000010
-#define A_CLK		0x00000001
+#define CRB	(1 << 4)
+#define CRA	(1 << 0)
 
 /* IO SHIFT / MACRO */
 #define BI_SHIFT	12
@@ -146,11 +146,20 @@ struct fsi_priv {
 	void __iomem *base;
 	struct fsi_master *master;
 
-	int chan_num;
 	struct fsi_stream playback;
 	struct fsi_stream capture;
 
+	int chan_num:16;
+	int clk_master:1;
+
 	long rate;
+
+	/* for suspend/resume */
+	u32 saved_do_fmt;
+	u32 saved_di_fmt;
+	u32 saved_ckg1;
+	u32 saved_ckg2;
+	u32 saved_out_sel;
 };
 
 struct fsi_core {
@@ -171,6 +180,14 @@ struct fsi_master {
 	struct fsi_core *core;
 	struct sh_fsi_platform_info *info;
 	spinlock_t lock;
+
+	/* for suspend/resume */
+	u32 saved_a_mclk;
+	u32 saved_b_mclk;
+	u32 saved_iemsk;
+	u32 saved_imsk;
+	u32 saved_clk_rst;
+	u32 saved_soft_rst;
 };
 
 /*
@@ -244,6 +261,11 @@ static struct fsi_master *fsi_get_master(struct fsi_priv *fsi)
 	return fsi->master;
 }
 
+static int fsi_is_clk_master(struct fsi_priv *fsi)
+{
+	return fsi->clk_master;
+}
+
 static int fsi_is_port_a(struct fsi_priv *fsi)
 {
 	return fsi->master->base == fsi->base;
@@ -535,20 +557,45 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
 }
 
 /*
- *		ctrl function
+ *		clock function
  */
+#define fsi_module_init(m, d)	__fsi_module_clk_ctrl(m, d, 1)
+#define fsi_module_kill(m, d)	__fsi_module_clk_ctrl(m, d, 0)
+static void __fsi_module_clk_ctrl(struct fsi_master *master,
+				  struct device *dev,
+				  int enable)
+{
+	pm_runtime_get_sync(dev);
+
+	if (enable) {
+		/* enable only SR */
+		fsi_master_mask_set(master, SOFT_RST, FSISR, FSISR);
+		fsi_master_mask_set(master, SOFT_RST, PASR | PBSR, 0);
+	} else {
+		/* clear all registers */
+		fsi_master_mask_set(master, SOFT_RST, FSISR, 0);
+	}
 
-static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable)
+	pm_runtime_put_sync(dev);
+}
+
+#define fsi_port_start(f)	__fsi_port_clk_ctrl(f, 1)
+#define fsi_port_stop(f)	__fsi_port_clk_ctrl(f, 0)
+static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int enable)
 {
-	u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4);
 	struct fsi_master *master = fsi_get_master(fsi);
+	u32 soft = fsi_is_port_a(fsi) ? PASR : PBSR;
+	u32 clk  = fsi_is_port_a(fsi) ? CRA  : CRB;
+	int is_master = fsi_is_clk_master(fsi);
 
-	if (enable)
-		fsi_master_mask_set(master, CLK_RST, val, val);
-	else
-		fsi_master_mask_set(master, CLK_RST, val, 0);
+	fsi_master_mask_set(master, SOFT_RST, soft, (enable) ? soft : 0);
+	if (is_master)
+		fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
 }
 
+/*
+ *		ctrl function
+ */
 static void fsi_fifo_init(struct fsi_priv *fsi,
 			  int is_play,
 			  struct snd_soc_dai *dai)
@@ -601,18 +648,6 @@ static void fsi_fifo_init(struct fsi_priv *fsi,
 	}
 }
 
-static void fsi_soft_all_reset(struct fsi_master *master)
-{
-	/* port AB reset */
-	fsi_master_mask_set(master, SOFT_RST, PASR | PBSR, 0);
-	mdelay(10);
-
-	/* soft reset */
-	fsi_master_mask_set(master, SOFT_RST, FSISR, 0);
-	fsi_master_mask_set(master, SOFT_RST, FSISR, FSISR);
-	mdelay(10);
-}
-
 static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream)
 {
 	struct snd_pcm_runtime *runtime;
@@ -793,14 +828,13 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
 	struct fsi_priv *fsi = fsi_get_priv(substream);
 	int is_play = fsi_is_play(substream);
 	struct fsi_master *master = fsi_get_master(fsi);
-	set_rate_func set_rate;
+	set_rate_func set_rate = fsi_get_info_set_rate(master);
 
 	fsi_irq_disable(fsi, is_play);
-	fsi_clk_ctrl(fsi, 0);
 
-	set_rate = fsi_get_info_set_rate(master);
-	if (set_rate && fsi->rate)
+	if (fsi_is_clk_master(fsi))
 		set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0);
+
 	fsi->rate = 0;
 
 	pm_runtime_put_sync(dai->dev);
@@ -821,8 +855,10 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 				frames_to_bytes(runtime, runtime->period_size));
 		ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi);
 		fsi_irq_enable(fsi, is_play);
+		fsi_port_start(fsi);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
+		fsi_port_stop(fsi);
 		fsi_irq_disable(fsi, is_play);
 		fsi_stream_pop(fsi, is_play);
 		break;
@@ -876,6 +912,8 @@ static int fsi_set_fmt_spdif(struct fsi_priv *fsi)
 static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct fsi_priv *fsi = fsi_get_priv_frm_dai(dai);
+	struct fsi_master *master = fsi_get_master(fsi);
+	set_rate_func set_rate = fsi_get_info_set_rate(master);
 	u32 flags = fsi_get_info_flags(fsi);
 	u32 data = 0;
 	int ret;
@@ -886,6 +924,7 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
 		data = DIMD | DOMD;
+		fsi->clk_master = 1;
 		break;
 	case SND_SOC_DAIFMT_CBS_CFS:
 		break;
@@ -893,6 +932,13 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		ret = -EINVAL;
 		goto set_fmt_exit;
 	}
+
+	if (fsi_is_clk_master(fsi) && !set_rate) {
+		dev_err(dai->dev, "platform doesn't have set_rate\n");
+		ret = -EINVAL;
+		goto set_fmt_exit;
+	}
+
 	fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data);
 
 	/* set format */
@@ -919,13 +965,12 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
 {
 	struct fsi_priv *fsi = fsi_get_priv(substream);
 	struct fsi_master *master = fsi_get_master(fsi);
-	set_rate_func set_rate;
+	set_rate_func set_rate = fsi_get_info_set_rate(master);
 	int fsi_ver = master->core->ver;
 	long rate = params_rate(params);
 	int ret;
 
-	set_rate = fsi_get_info_set_rate(master);
-	if (!set_rate)
+	if (!fsi_is_clk_master(fsi))
 		return 0;
 
 	ret = set_rate(dai->dev, fsi_is_port_a(fsi), rate, 1);
@@ -987,7 +1032,6 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
 
 		fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data);
 		udelay(10);
-		fsi_clk_ctrl(fsi, 1);
 		ret = 0;
 	}
 
@@ -1202,9 +1246,7 @@ static int fsi_probe(struct platform_device *pdev)
 	pm_runtime_enable(&pdev->dev);
 	dev_set_drvdata(&pdev->dev, master);
 
-	pm_runtime_get_sync(&pdev->dev);
-	fsi_soft_all_reset(master);
-	pm_runtime_put_sync(&pdev->dev);
+	fsi_module_init(master, &pdev->dev);
 
 	ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED,
 			  id_entry->name, master);
@@ -1248,6 +1290,8 @@ static int fsi_remove(struct platform_device *pdev)
 
 	master = dev_get_drvdata(&pdev->dev);
 
+	fsi_module_kill(master, &pdev->dev);
+
 	free_irq(master->irq, master);
 	pm_runtime_disable(&pdev->dev);
 
@@ -1260,6 +1304,82 @@ static int fsi_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static void __fsi_suspend(struct fsi_priv *fsi,
+			  struct device *dev,
+			  set_rate_func set_rate)
+{
+	fsi->saved_do_fmt	= fsi_reg_read(fsi, DO_FMT);
+	fsi->saved_di_fmt	= fsi_reg_read(fsi, DI_FMT);
+	fsi->saved_ckg1		= fsi_reg_read(fsi, CKG1);
+	fsi->saved_ckg2		= fsi_reg_read(fsi, CKG2);
+	fsi->saved_out_sel	= fsi_reg_read(fsi, OUT_SEL);
+
+	if (fsi_is_clk_master(fsi))
+		set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 0);
+}
+
+static void __fsi_resume(struct fsi_priv *fsi,
+			 struct device *dev,
+			 set_rate_func set_rate)
+{
+	fsi_reg_write(fsi, DO_FMT,	fsi->saved_do_fmt);
+	fsi_reg_write(fsi, DI_FMT,	fsi->saved_di_fmt);
+	fsi_reg_write(fsi, CKG1,	fsi->saved_ckg1);
+	fsi_reg_write(fsi, CKG2,	fsi->saved_ckg2);
+	fsi_reg_write(fsi, OUT_SEL,	fsi->saved_out_sel);
+
+	if (fsi_is_clk_master(fsi))
+		set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 1);
+}
+
+static int fsi_suspend(struct device *dev)
+{
+	struct fsi_master *master = dev_get_drvdata(dev);
+	set_rate_func set_rate = fsi_get_info_set_rate(master);
+
+	pm_runtime_get_sync(dev);
+
+	__fsi_suspend(&master->fsia, dev, set_rate);
+	__fsi_suspend(&master->fsib, dev, set_rate);
+
+	master->saved_a_mclk	= fsi_core_read(master, a_mclk);
+	master->saved_b_mclk	= fsi_core_read(master, b_mclk);
+	master->saved_iemsk	= fsi_core_read(master, iemsk);
+	master->saved_imsk	= fsi_core_read(master, imsk);
+	master->saved_clk_rst	= fsi_master_read(master, CLK_RST);
+	master->saved_soft_rst	= fsi_master_read(master, SOFT_RST);
+
+	fsi_module_kill(master, dev);
+
+	pm_runtime_put_sync(dev);
+
+	return 0;
+}
+
+static int fsi_resume(struct device *dev)
+{
+	struct fsi_master *master = dev_get_drvdata(dev);
+	set_rate_func set_rate = fsi_get_info_set_rate(master);
+
+	pm_runtime_get_sync(dev);
+
+	fsi_module_init(master, dev);
+
+	fsi_master_mask_set(master, SOFT_RST, 0xffff, master->saved_soft_rst);
+	fsi_master_mask_set(master, CLK_RST, 0xffff, master->saved_clk_rst);
+	fsi_core_mask_set(master, a_mclk, 0xffff, master->saved_a_mclk);
+	fsi_core_mask_set(master, b_mclk, 0xffff, master->saved_b_mclk);
+	fsi_core_mask_set(master, iemsk, 0xffff, master->saved_iemsk);
+	fsi_core_mask_set(master, imsk, 0xffff, master->saved_imsk);
+
+	__fsi_resume(&master->fsia, dev, set_rate);
+	__fsi_resume(&master->fsib, dev, set_rate);
+
+	pm_runtime_put_sync(dev);
+
+	return 0;
+}
+
 static int fsi_runtime_nop(struct device *dev)
 {
 	/* Runtime PM callback shared between ->runtime_suspend()
@@ -1273,6 +1393,8 @@ static int fsi_runtime_nop(struct device *dev)
 }
 
 static struct dev_pm_ops fsi_pm_ops = {
+	.suspend		= fsi_suspend,
+	.resume			= fsi_resume,
 	.runtime_suspend	= fsi_runtime_nop,
 	.runtime_resume		= fsi_runtime_nop,
 };
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index 5d76da43b14c..06b7b81a1601 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -20,40 +20,28 @@
 
 #include <trace/events/asoc.h>
 
-static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
-				     unsigned int reg)
+#ifdef CONFIG_SPI_MASTER
+static int do_spi_write(void *control, const char *data, int len)
 {
+	struct spi_device *spi = control;
 	int ret;
-	unsigned int val;
-
-	if (reg >= codec->driver->reg_cache_size ||
-		snd_soc_codec_volatile_register(codec, reg) ||
-		codec->cache_bypass) {
-			if (codec->cache_only)
-				return -1;
-
-			BUG_ON(!codec->hw_read);
-			return codec->hw_read(codec, reg);
-	}
 
-	ret = snd_soc_cache_read(codec, reg, &val);
+	ret = spi_write(spi, data, len);
 	if (ret < 0)
-		return -1;
-	return val;
+		return ret;
+
+	return len;
 }
+#endif
 
-static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
-			     unsigned int value)
+static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg,
+		       unsigned int value, const void *data, int len)
 {
-	u8 data[2];
 	int ret;
 
-	data[0] = (reg << 4) | ((value >> 8) & 0x000f);
-	data[1] = value & 0x00ff;
-
 	if (!snd_soc_codec_volatile_register(codec, reg) &&
-		reg < codec->driver->reg_cache_size &&
-		!codec->cache_bypass) {
+	    reg < codec->driver->reg_cache_size &&
+	    !codec->cache_bypass) {
 		ret = snd_soc_cache_write(codec, reg, value);
 		if (ret < 0)
 			return -1;
@@ -64,8 +52,8 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
 		return 0;
 	}
 
-	ret = codec->hw_write(codec->control_data, data, 2);
-	if (ret == 2)
+	ret = codec->hw_write(codec->control_data, data, len);
+	if (ret == len)
 		return 0;
 	if (ret < 0)
 		return ret;
@@ -73,50 +61,19 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
 		return -EIO;
 }
 
-#if defined(CONFIG_SPI_MASTER)
-static int snd_soc_4_12_spi_write(void *control_data, const char *data,
-				 int len)
-{
-	struct spi_device *spi = control_data;
-	struct spi_transfer t;
-	struct spi_message m;
-	u8 msg[2];
-
-	if (len <= 0)
-		return 0;
-
-	msg[0] = data[1];
-	msg[1] = data[0];
-
-	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;
-}
-#else
-#define snd_soc_4_12_spi_write NULL
-#endif
-
-static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
-				     unsigned int reg)
+static unsigned int do_hw_read(struct snd_soc_codec *codec, unsigned int reg)
 {
 	int ret;
 	unsigned int val;
 
 	if (reg >= codec->driver->reg_cache_size ||
-		snd_soc_codec_volatile_register(codec, reg) ||
-		codec->cache_bypass) {
-			if (codec->cache_only)
-				return -1;
+	    snd_soc_codec_volatile_register(codec, reg) ||
+	    codec->cache_bypass) {
+		if (codec->cache_only)
+			return -1;
 
-			BUG_ON(!codec->hw_read);
-			return codec->hw_read(codec, reg);
+		BUG_ON(!codec->hw_read);
+		return codec->hw_read(codec, reg);
 	}
 
 	ret = snd_soc_cache_read(codec, reg, &val);
@@ -125,259 +82,117 @@ static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
 	return val;
 }
 
-static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
-			     unsigned int value)
+static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
+				      unsigned int reg)
 {
-	u8 data[2];
-	int ret;
-
-	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
-	data[1] = value & 0x00ff;
-
-	if (!snd_soc_codec_volatile_register(codec, reg) &&
-		reg < codec->driver->reg_cache_size &&
-		!codec->cache_bypass) {
-		ret = snd_soc_cache_write(codec, reg, value);
-		if (ret < 0)
-			return -1;
-	}
-
-	if (codec->cache_only) {
-		codec->cache_sync = 1;
-		return 0;
-	}
-
-	ret = codec->hw_write(codec->control_data, data, 2);
-	if (ret == 2)
-		return 0;
-	if (ret < 0)
-		return ret;
-	else
-		return -EIO;
+	return do_hw_read(codec, reg);
 }
 
-#if defined(CONFIG_SPI_MASTER)
-static int snd_soc_7_9_spi_write(void *control_data, const char *data,
-				 int len)
+static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
+			      unsigned int value)
 {
-	struct spi_device *spi = control_data;
-	struct spi_transfer t;
-	struct spi_message m;
-	u8 msg[2];
+	u16 data;
 
-	if (len <= 0)
-		return 0;
+	data = cpu_to_be16((reg << 12) | (value & 0xffffff));
 
-	msg[0] = data[0];
-	msg[1] = data[1];
+	return do_hw_write(codec, reg, value, &data, 2);
+}
 
-	spi_message_init(&m);
-	memset(&t, 0, sizeof t);
+static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
+				     unsigned int reg)
+{
+	return do_hw_read(codec, reg);
+}
 
-	t.tx_buf = &msg[0];
-	t.len = len;
+static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
+			     unsigned int value)
+{
+	u8 data[2];
 
-	spi_message_add_tail(&t, &m);
-	spi_sync(spi, &m);
+	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+	data[1] = value & 0x00ff;
 
-	return len;
+	return do_hw_write(codec, reg, value, data, 2);
 }
-#else
-#define snd_soc_7_9_spi_write NULL
-#endif
 
 static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
 			     unsigned int value)
 {
 	u8 data[2];
-	int ret;
 
 	reg &= 0xff;
 	data[0] = reg;
 	data[1] = value & 0xff;
 
-	if (!snd_soc_codec_volatile_register(codec, reg) &&
-		reg < codec->driver->reg_cache_size &&
-		!codec->cache_bypass) {
-		ret = snd_soc_cache_write(codec, reg, value);
-		if (ret < 0)
-			return -1;
-	}
-
-	if (codec->cache_only) {
-		codec->cache_sync = 1;
-		return 0;
-	}
-
-	if (codec->hw_write(codec->control_data, data, 2) == 2)
-		return 0;
-	else
-		return -EIO;
+	return do_hw_write(codec, reg, value, data, 2);
 }
 
 static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
 				     unsigned int reg)
 {
-	int ret;
-	unsigned int val;
-
-	reg &= 0xff;
-	if (reg >= codec->driver->reg_cache_size ||
-		snd_soc_codec_volatile_register(codec, reg) ||
-		codec->cache_bypass) {
-			if (codec->cache_only)
-				return -1;
-
-			BUG_ON(!codec->hw_read);
-			return codec->hw_read(codec, reg);
-	}
-
-	ret = snd_soc_cache_read(codec, reg, &val);
-	if (ret < 0)
-		return -1;
-	return val;
-}
-
-#if defined(CONFIG_SPI_MASTER)
-static int snd_soc_8_8_spi_write(void *control_data, const char *data,
-				 int len)
-{
-	struct spi_device *spi = control_data;
-	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;
+	return do_hw_read(codec, reg);
 }
-#else
-#define snd_soc_8_8_spi_write NULL
-#endif
 
 static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
 			      unsigned int value)
 {
 	u8 data[3];
-	int ret;
 
 	data[0] = reg;
 	data[1] = (value >> 8) & 0xff;
 	data[2] = value & 0xff;
 
-	if (!snd_soc_codec_volatile_register(codec, reg) &&
-		reg < codec->driver->reg_cache_size &&
-		!codec->cache_bypass) {
-		ret = snd_soc_cache_write(codec, reg, value);
-		if (ret < 0)
-			return -1;
-	}
-
-	if (codec->cache_only) {
-		codec->cache_sync = 1;
-		return 0;
-	}
-
-	if (codec->hw_write(codec->control_data, data, 3) == 3)
-		return 0;
-	else
-		return -EIO;
+	return do_hw_write(codec, reg, value, data, 3);
 }
 
 static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
 				      unsigned int reg)
 {
-	int ret;
-	unsigned int val;
-
-	if (reg >= codec->driver->reg_cache_size ||
-	    snd_soc_codec_volatile_register(codec, reg) ||
-	    codec->cache_bypass) {
-		if (codec->cache_only)
-			return -1;
-
-		BUG_ON(!codec->hw_read);
-		return codec->hw_read(codec, reg);
-	}
-
-	ret = snd_soc_cache_read(codec, reg, &val);
-	if (ret < 0)
-		return -1;
-	return val;
-}
-
-#if defined(CONFIG_SPI_MASTER)
-static int snd_soc_8_16_spi_write(void *control_data, const char *data,
-				 int len)
-{
-	struct spi_device *spi = control_data;
-	struct spi_transfer t;
-	struct spi_message m;
-	u8 msg[3];
-
-	if (len <= 0)
-		return 0;
-
-	msg[0] = data[0];
-	msg[1] = data[1];
-	msg[2] = data[2];
-
-	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;
+	return do_hw_read(codec, reg);
 }
-#else
-#define snd_soc_8_16_spi_write NULL
-#endif
 
 #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
-static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
-					  unsigned int r)
+static unsigned int do_i2c_read(struct snd_soc_codec *codec,
+				void *reg, int reglen,
+				void *data, int datalen)
 {
 	struct i2c_msg xfer[2];
-	u8 reg = r;
-	u8 data;
 	int ret;
 	struct i2c_client *client = codec->control_data;
 
 	/* Write register */
 	xfer[0].addr = client->addr;
 	xfer[0].flags = 0;
-	xfer[0].len = 1;
-	xfer[0].buf = &reg;
+	xfer[0].len = reglen;
+	xfer[0].buf = reg;
 
 	/* Read data */
 	xfer[1].addr = client->addr;
 	xfer[1].flags = I2C_M_RD;
-	xfer[1].len = 1;
-	xfer[1].buf = &data;
+	xfer[1].len = datalen;
+	xfer[1].buf = data;
 
 	ret = i2c_transfer(client->adapter, xfer, 2);
-	if (ret != 2) {
-		dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+	if (ret == 2)
 		return 0;
-	}
+	else if (ret < 0)
+		return ret;
+	else
+		return -EIO;
+}
+#endif
 
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
+					 unsigned int r)
+{
+	u8 reg = r;
+	u8 data;
+	int ret;
+
+	ret = do_i2c_read(codec, &reg, 1, &data, 1);
+	if (ret < 0)
+		return 0;
 	return data;
 }
 #else
@@ -388,30 +203,13 @@ static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
 static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
 					  unsigned int r)
 {
-	struct i2c_msg xfer[2];
 	u8 reg = r;
 	u16 data;
 	int ret;
-	struct i2c_client *client = codec->control_data;
 
-	/* Write register */
-	xfer[0].addr = client->addr;
-	xfer[0].flags = 0;
-	xfer[0].len = 1;
-	xfer[0].buf = &reg;
-
-	/* Read data */
-	xfer[1].addr = client->addr;
-	xfer[1].flags = I2C_M_RD;
-	xfer[1].len = 2;
-	xfer[1].buf = (u8 *)&data;
-
-	ret = i2c_transfer(client->adapter, xfer, 2);
-	if (ret != 2) {
-		dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+	ret = do_i2c_read(codec, &reg, 1, &data, 2);
+	if (ret < 0)
 		return 0;
-	}
-
 	return (data >> 8) | ((data & 0xff) << 8);
 }
 #else
@@ -422,30 +220,13 @@ static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
 static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
 					  unsigned int r)
 {
-	struct i2c_msg xfer[2];
 	u16 reg = r;
 	u8 data;
 	int ret;
-	struct i2c_client *client = codec->control_data;
-
-	/* Write register */
-	xfer[0].addr = client->addr;
-	xfer[0].flags = 0;
-	xfer[0].len = 2;
-	xfer[0].buf = (u8 *)&reg;
-
-	/* Read data */
-	xfer[1].addr = client->addr;
-	xfer[1].flags = I2C_M_RD;
-	xfer[1].len = 1;
-	xfer[1].buf = &data;
 
-	ret = i2c_transfer(client->adapter, xfer, 2);
-	if (ret != 2) {
-		dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+	ret = do_i2c_read(codec, &reg, 2, &data, 1);
+	if (ret < 0)
 		return 0;
-	}
-
 	return data;
 }
 #else
@@ -453,120 +234,34 @@ static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
 #endif
 
 static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
-				     unsigned int reg)
+				      unsigned int reg)
 {
-	int ret;
-	unsigned int val;
-
-	reg &= 0xff;
-	if (reg >= codec->driver->reg_cache_size ||
-		snd_soc_codec_volatile_register(codec, reg) ||
-		codec->cache_bypass) {
-			if (codec->cache_only)
-				return -1;
-
-			BUG_ON(!codec->hw_read);
-			return codec->hw_read(codec, reg);
-	}
-
-	ret = snd_soc_cache_read(codec, reg, &val);
-	if (ret < 0)
-		return -1;
-	return val;
+	return do_hw_read(codec, reg);
 }
 
 static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
-			     unsigned int value)
+			      unsigned int value)
 {
 	u8 data[3];
-	int ret;
 
 	data[0] = (reg >> 8) & 0xff;
 	data[1] = reg & 0xff;
 	data[2] = value;
 
-	reg &= 0xff;
-	if (!snd_soc_codec_volatile_register(codec, reg) &&
-		reg < codec->driver->reg_cache_size &&
-		!codec->cache_bypass) {
-		ret = snd_soc_cache_write(codec, reg, value);
-		if (ret < 0)
-			return -1;
-	}
-
-	if (codec->cache_only) {
-		codec->cache_sync = 1;
-		return 0;
-	}
-
-	ret = codec->hw_write(codec->control_data, data, 3);
-	if (ret == 3)
-		return 0;
-	if (ret < 0)
-		return ret;
-	else
-		return -EIO;
-}
-
-#if defined(CONFIG_SPI_MASTER)
-static int snd_soc_16_8_spi_write(void *control_data, const char *data,
-				 int len)
-{
-	struct spi_device *spi = control_data;
-	struct spi_transfer t;
-	struct spi_message m;
-	u8 msg[3];
-
-	if (len <= 0)
-		return 0;
-
-	msg[0] = data[0];
-	msg[1] = data[1];
-	msg[2] = data[2];
-
-	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;
+	return do_hw_write(codec, reg, value, data, 3);
 }
-#else
-#define snd_soc_16_8_spi_write NULL
-#endif
 
 #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
 static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
 					   unsigned int r)
 {
-	struct i2c_msg xfer[2];
 	u16 reg = cpu_to_be16(r);
 	u16 data;
 	int ret;
-	struct i2c_client *client = codec->control_data;
-
-	/* Write register */
-	xfer[0].addr = client->addr;
-	xfer[0].flags = 0;
-	xfer[0].len = 2;
-	xfer[0].buf = (u8 *)&reg;
 
-	/* Read data */
-	xfer[1].addr = client->addr;
-	xfer[1].flags = I2C_M_RD;
-	xfer[1].len = 2;
-	xfer[1].buf = (u8 *)&data;
-
-	ret = i2c_transfer(client->adapter, xfer, 2);
-	if (ret != 2) {
-		dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+	ret = do_i2c_read(codec, &reg, 2, &data, 2);
+	if (ret < 0)
 		return 0;
-	}
-
 	return be16_to_cpu(data);
 }
 #else
@@ -576,52 +271,59 @@ static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
 static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
 				       unsigned int reg)
 {
-	int ret;
-	unsigned int val;
-
-	if (reg >= codec->driver->reg_cache_size ||
-	    snd_soc_codec_volatile_register(codec, reg) ||
-	    codec->cache_bypass) {
-		if (codec->cache_only)
-			return -1;
-
-		BUG_ON(!codec->hw_read);
-		return codec->hw_read(codec, reg);
-	}
-
-	ret = snd_soc_cache_read(codec, reg, &val);
-	if (ret < 0)
-		return -1;
-
-	return val;
+	return do_hw_read(codec, reg);
 }
 
 static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
 			       unsigned int value)
 {
 	u8 data[4];
-	int ret;
 
 	data[0] = (reg >> 8) & 0xff;
 	data[1] = reg & 0xff;
 	data[2] = (value >> 8) & 0xff;
 	data[3] = value & 0xff;
 
-	if (!snd_soc_codec_volatile_register(codec, reg) &&
-		reg < codec->driver->reg_cache_size &&
-		!codec->cache_bypass) {
-		ret = snd_soc_cache_write(codec, reg, value);
-		if (ret < 0)
-			return -1;
-	}
+	return do_hw_write(codec, reg, value, data, 4);
+}
 
-	if (codec->cache_only) {
-		codec->cache_sync = 1;
-		return 0;
+/* Primitive bulk write support for soc-cache.  The data pointed to by
+ * `data' needs to already be in the form the hardware expects
+ * including any leading register specific data.  Any data written
+ * through this function will not go through the cache as it only
+ * handles writing to volatile or out of bounds registers.
+ */
+static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg,
+				     const void *data, size_t len)
+{
+	int ret;
+
+	/* To ensure that we don't get out of sync with the cache, check
+	 * whether the base register is volatile or if we've directly asked
+	 * to bypass the cache.  Out of bounds registers are considered
+	 * volatile.
+	 */
+	if (!codec->cache_bypass
+	    && !snd_soc_codec_volatile_register(codec, reg)
+	    && reg < codec->driver->reg_cache_size)
+		return -EINVAL;
+
+	switch (codec->control_type) {
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+	case SND_SOC_I2C:
+		ret = i2c_master_send(codec->control_data, data, len);
+		break;
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	case SND_SOC_SPI:
+		ret = spi_write(codec->control_data, data, len);
+		break;
+#endif
+	default:
+		BUG();
 	}
 
-	ret = codec->hw_write(codec->control_data, data, 4);
-	if (ret == 4)
+	if (ret == len)
 		return 0;
 	if (ret < 0)
 		return ret;
@@ -629,79 +331,40 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
 		return -EIO;
 }
 
-#if defined(CONFIG_SPI_MASTER)
-static int snd_soc_16_16_spi_write(void *control_data, const char *data,
-				 int len)
-{
-	struct spi_device *spi = control_data;
-	struct spi_transfer t;
-	struct spi_message m;
-	u8 msg[4];
-
-	if (len <= 0)
-		return 0;
-
-	msg[0] = data[0];
-	msg[1] = data[1];
-	msg[2] = data[2];
-	msg[3] = data[3];
-
-	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;
-}
-#else
-#define snd_soc_16_16_spi_write NULL
-#endif
-
 static struct {
 	int addr_bits;
 	int data_bits;
 	int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
-	int (*spi_write)(void *, const char *, int);
 	unsigned int (*read)(struct snd_soc_codec *, unsigned int);
 	unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
 } io_types[] = {
 	{
 		.addr_bits = 4, .data_bits = 12,
 		.write = snd_soc_4_12_write, .read = snd_soc_4_12_read,
-		.spi_write = snd_soc_4_12_spi_write,
 	},
 	{
 		.addr_bits = 7, .data_bits = 9,
 		.write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
-		.spi_write = snd_soc_7_9_spi_write,
 	},
 	{
 		.addr_bits = 8, .data_bits = 8,
 		.write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
 		.i2c_read = snd_soc_8_8_read_i2c,
-		.spi_write = snd_soc_8_8_spi_write,
 	},
 	{
 		.addr_bits = 8, .data_bits = 16,
 		.write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
 		.i2c_read = snd_soc_8_16_read_i2c,
-		.spi_write = snd_soc_8_16_spi_write,
 	},
 	{
 		.addr_bits = 16, .data_bits = 8,
 		.write = snd_soc_16_8_write, .read = snd_soc_16_8_read,
 		.i2c_read = snd_soc_16_8_read_i2c,
-		.spi_write = snd_soc_16_8_spi_write,
 	},
 	{
 		.addr_bits = 16, .data_bits = 16,
 		.write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
 		.i2c_read = snd_soc_16_16_read_i2c,
-		.spi_write = snd_soc_16_16_spi_write,
 	},
 };
 
@@ -709,7 +372,6 @@ static struct {
  * snd_soc_codec_set_cache_io: Set up standard I/O functions.
  *
  * @codec: CODEC to configure.
- * @type: Type of cache.
  * @addr_bits: Number of bits of register address data.
  * @data_bits: Number of bits of data per register.
  * @control: Control bus used.
@@ -744,6 +406,7 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
 
 	codec->write = io_types[i].write;
 	codec->read = io_types[i].read;
+	codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;
 
 	switch (control) {
 	case SND_SOC_CUSTOM:
@@ -762,8 +425,9 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_SPI:
-		if (io_types[i].spi_write)
-			codec->hw_write = io_types[i].spi_write;
+#ifdef CONFIG_SPI_MASTER
+		codec->hw_write = do_spi_write;
+#endif
 
 		codec->control_data = container_of(codec->dev,
 						   struct spi_device,
@@ -889,6 +553,8 @@ static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
 		rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
 		if (rbnode->value == rbnode->defval)
 			continue;
+		WARN_ON(codec->writable_register &&
+			codec->writable_register(codec, rbnode->reg));
 		ret = snd_soc_cache_read(codec, rbnode->reg, &val);
 		if (ret)
 			return ret;
@@ -1149,6 +815,8 @@ static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec)
 
 	lzo_blocks = codec->reg_cache;
 	for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
+		WARN_ON(codec->writable_register &&
+			codec->writable_register(codec, i));
 		ret = snd_soc_cache_read(codec, i, &val);
 		if (ret)
 			return ret;
@@ -1407,6 +1075,8 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
 
 	codec_drv = codec->driver;
 	for (i = 0; i < codec_drv->reg_cache_size; ++i) {
+		WARN_ON(codec->writable_register &&
+			codec->writable_register(codec, i));
 		ret = snd_soc_cache_read(codec, i, &val);
 		if (ret)
 			return ret;
@@ -1523,7 +1193,7 @@ int snd_soc_cache_init(struct snd_soc_codec *codec)
 				codec->cache_ops->name, codec->name);
 		return codec->cache_ops->init(codec);
 	}
-	return -EINVAL;
+	return -ENOSYS;
 }
 
 /*
@@ -1538,7 +1208,7 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec)
 				codec->cache_ops->name, codec->name);
 		return codec->cache_ops->exit(codec);
 	}
-	return -EINVAL;
+	return -ENOSYS;
 }
 
 /**
@@ -1562,7 +1232,7 @@ int snd_soc_cache_read(struct snd_soc_codec *codec,
 	}
 
 	mutex_unlock(&codec->cache_rw_mutex);
-	return -EINVAL;
+	return -ENOSYS;
 }
 EXPORT_SYMBOL_GPL(snd_soc_cache_read);
 
@@ -1587,7 +1257,7 @@ int snd_soc_cache_write(struct snd_soc_codec *codec,
 	}
 
 	mutex_unlock(&codec->cache_rw_mutex);
-	return -EINVAL;
+	return -ENOSYS;
 }
 EXPORT_SYMBOL_GPL(snd_soc_cache_write);
 
@@ -1610,7 +1280,7 @@ int snd_soc_cache_sync(struct snd_soc_codec *codec)
 	}
 
 	if (!codec->cache_ops || !codec->cache_ops->sync)
-		return -EINVAL;
+		return -ENOSYS;
 
 	if (codec->cache_ops->name)
 		name = codec->cache_ops->name;
@@ -1677,3 +1347,17 @@ int snd_soc_default_readable_register(struct snd_soc_codec *codec,
 	return codec->driver->reg_access_default[index].read;
 }
 EXPORT_SYMBOL_GPL(snd_soc_default_readable_register);
+
+int snd_soc_default_writable_register(struct snd_soc_codec *codec,
+				      unsigned int reg)
+{
+	int index;
+
+	if (reg >= codec->driver->reg_cache_size)
+		return 1;
+	index = snd_soc_get_reg_access_index(codec, reg);
+	if (index < 0)
+		return 0;
+	return codec->driver->reg_access_default[index].write;
+}
+EXPORT_SYMBOL_GPL(snd_soc_default_writable_register);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index dd55d1069468..bb7cd5812945 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -242,7 +242,7 @@ static ssize_t codec_reg_write_file(struct file *file,
 		const char __user *user_buf, size_t count, loff_t *ppos)
 {
 	char buf[32];
-	int buf_size;
+	size_t buf_size;
 	char *start = buf;
 	unsigned long reg, value;
 	int step = 1;
@@ -302,13 +302,7 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
 		printk(KERN_WARNING
 		       "ASoC: Failed to create codec register debugfs file\n");
 
-	codec->dapm.debugfs_dapm = debugfs_create_dir("dapm",
-						 codec->debugfs_codec_root);
-	if (!codec->dapm.debugfs_dapm)
-		printk(KERN_WARNING
-		       "Failed to create DAPM debugfs directory\n");
-
-	snd_soc_dapm_debugfs_init(&codec->dapm);
+	snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root);
 }
 
 static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
@@ -555,7 +549,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
 		}
 	}
 
-	if (platform->driver->ops->open) {
+	if (platform->driver->ops && platform->driver->ops->open) {
 		ret = platform->driver->ops->open(substream);
 		if (ret < 0) {
 			printk(KERN_ERR "asoc: can't open platform %s\n", platform->name);
@@ -685,7 +679,7 @@ machine_err:
 		codec_dai->driver->ops->shutdown(substream, codec_dai);
 
 codec_dai_err:
-	if (platform->driver->ops->close)
+	if (platform->driver->ops && platform->driver->ops->close)
 		platform->driver->ops->close(substream);
 
 platform_err:
@@ -767,7 +761,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
 	if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
 		rtd->dai_link->ops->shutdown(substream);
 
-	if (platform->driver->ops->close)
+	if (platform->driver->ops && platform->driver->ops->close)
 		platform->driver->ops->close(substream);
 	cpu_dai->runtime = NULL;
 
@@ -810,7 +804,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
 		}
 	}
 
-	if (platform->driver->ops->prepare) {
+	if (platform->driver->ops && platform->driver->ops->prepare) {
 		ret = platform->driver->ops->prepare(substream);
 		if (ret < 0) {
 			printk(KERN_ERR "asoc: platform prepare error\n");
@@ -899,7 +893,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
 		}
 	}
 
-	if (platform->driver->ops->hw_params) {
+	if (platform->driver->ops && platform->driver->ops->hw_params) {
 		ret = platform->driver->ops->hw_params(substream, params);
 		if (ret < 0) {
 			printk(KERN_ERR "asoc: platform %s hw params failed\n",
@@ -952,7 +946,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
 		rtd->dai_link->ops->hw_free(substream);
 
 	/* free any DMA resources */
-	if (platform->driver->ops->hw_free)
+	if (platform->driver->ops && platform->driver->ops->hw_free)
 		platform->driver->ops->hw_free(substream);
 
 	/* now free hw params for the DAIs  */
@@ -980,7 +974,7 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 			return ret;
 	}
 
-	if (platform->driver->ops->trigger) {
+	if (platform->driver->ops && platform->driver->ops->trigger) {
 		ret = platform->driver->ops->trigger(substream, cmd);
 		if (ret < 0)
 			return ret;
@@ -1009,7 +1003,7 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
 	snd_pcm_uframes_t offset = 0;
 	snd_pcm_sframes_t delay = 0;
 
-	if (platform->driver->ops->pointer)
+	if (platform->driver->ops && platform->driver->ops->pointer)
 		offset = platform->driver->ops->pointer(substream);
 
 	if (cpu_dai->driver->ops->delay)
@@ -1299,6 +1293,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
 	struct snd_soc_codec *codec;
 	struct snd_soc_platform *platform;
 	struct snd_soc_dai *codec_dai, *cpu_dai;
+	const char *platform_name;
 
 	if (rtd->complete)
 		return 1;
@@ -1351,13 +1346,18 @@ find_codec:
 			dai_link->codec_name);
 
 find_platform:
-	/* do we already have the CODEC DAI for this link ? */
-	if (rtd->platform) {
+	/* do we need a platform? */
+	if (rtd->platform)
 		goto out;
-	}
-	/* no, then find CPU DAI from registered DAIs*/
+
+	/* if there's no platform we match on the empty platform */
+	platform_name = dai_link->platform_name;
+	if (!platform_name)
+		platform_name = "snd-soc-dummy";
+
+	/* no, then find one from the set of registered platforms */
 	list_for_each_entry(platform, &platform_list, list) {
-		if (!strcmp(platform->name, dai_link->platform_name)) {
+		if (!strcmp(platform->name, platform_name)) {
 			rtd->platform = platform;
 			goto out;
 		}
@@ -1453,6 +1453,16 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num)
 	}
 }
 
+static void soc_remove_dai_links(struct snd_soc_card *card)
+{
+	int i;
+
+	for (i = 0; i < card->num_rtd; i++)
+		soc_remove_dai_link(card, i);
+
+	card->num_rtd = 0;
+}
+
 static void soc_set_name_prefix(struct snd_soc_card *card,
 				struct snd_soc_codec *codec)
 {
@@ -1483,6 +1493,12 @@ static int soc_probe_codec(struct snd_soc_card *card,
 	if (!try_module_get(codec->dev->driver->owner))
 		return -ENODEV;
 
+	soc_init_codec_debugfs(codec);
+
+	if (driver->dapm_widgets)
+		snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets,
+					  driver->num_dapm_widgets);
+
 	if (driver->probe) {
 		ret = driver->probe(codec);
 		if (ret < 0) {
@@ -1493,15 +1509,13 @@ static int soc_probe_codec(struct snd_soc_card *card,
 		}
 	}
 
-	if (driver->dapm_widgets)
-		snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets,
-					  driver->num_dapm_widgets);
+	if (driver->controls)
+		snd_soc_add_controls(codec, driver->controls,
+				     driver->num_controls);
 	if (driver->dapm_routes)
 		snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes,
 					driver->num_dapm_routes);
 
-	soc_init_codec_debugfs(codec);
-
 	/* mark codec as probed and add to card codec list */
 	codec->probed = 1;
 	list_add(&codec->card_list, &card->codec_dev_list);
@@ -1510,6 +1524,7 @@ static int soc_probe_codec(struct snd_soc_card *card,
 	return 0;
 
 err_probe:
+	soc_cleanup_codec_debugfs(codec);
 	module_put(codec->dev->driver->owner);
 
 	return ret;
@@ -1860,11 +1875,19 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
 	card->dapm.card = card;
 	list_add(&card->dapm.list, &card->dapm_list);
 
+#ifdef CONFIG_DEBUG_FS
+	snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root);
+#endif
+
 #ifdef CONFIG_PM_SLEEP
 	/* deferred resume work */
 	INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
 #endif
 
+	if (card->dapm_widgets)
+		snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
+					  card->num_dapm_widgets);
+
 	/* initialise the sound card only once */
 	if (card->probe) {
 		ret = card->probe(card);
@@ -1890,27 +1913,24 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
 		}
 	}
 
-	if (card->dapm_widgets)
-		snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
-					  card->num_dapm_widgets);
+	/* We should have a non-codec control add function but we don't */
+	if (card->controls)
+		snd_soc_add_controls(list_first_entry(&card->codec_dev_list,
+						      struct snd_soc_codec,
+						      card_list),
+				     card->controls,
+				     card->num_controls);
+
 	if (card->dapm_routes)
 		snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
 					card->num_dapm_routes);
 
-#ifdef CONFIG_DEBUG_FS
-	card->dapm.debugfs_dapm = debugfs_create_dir("dapm",
-						     card->debugfs_card_root);
-	if (!card->dapm.debugfs_dapm)
-		printk(KERN_WARNING
-		       "Failed to create card DAPM debugfs directory\n");
-
-	snd_soc_dapm_debugfs_init(&card->dapm);
-#endif
-
 	snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
-		 "%s",  card->name);
-	snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
 		 "%s", card->name);
+	snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
+		 "%s", card->long_name ? card->long_name : card->name);
+	snprintf(card->snd_card->driver, sizeof(card->snd_card->driver),
+		 "%s", card->driver_name ? card->driver_name : card->name);
 
 	if (card->late_probe) {
 		ret = card->late_probe(card);
@@ -1949,8 +1969,7 @@ probe_aux_dev_err:
 		soc_remove_aux_dev(card, i);
 
 probe_dai_err:
-	for (i = 0; i < card->num_links; i++)
-		soc_remove_dai_link(card, i);
+	soc_remove_dai_links(card);
 
 card_probe_error:
 	if (card->remove)
@@ -2012,8 +2031,7 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card)
 		soc_remove_aux_dev(card, i);
 
 	/* remove and free each DAI */
-	for (i = 0; i < card->num_rtd; i++)
-		soc_remove_dai_link(card, i);
+	soc_remove_dai_links(card);
 
 	soc_cleanup_card_debugfs(card);
 
@@ -2021,6 +2039,8 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card)
 	if (card->remove)
 		card->remove(card);
 
+	snd_soc_dapm_free(&card->dapm);
+
 	kfree(card->rtd);
 	snd_card_free(card->snd_card);
 	return 0;
@@ -2105,13 +2125,15 @@ static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 
 	rtd->pcm = pcm;
 	pcm->private_data = rtd;
-	soc_pcm_ops.mmap = platform->driver->ops->mmap;
-	soc_pcm_ops.pointer = platform->driver->ops->pointer;
-	soc_pcm_ops.ioctl = platform->driver->ops->ioctl;
-	soc_pcm_ops.copy = platform->driver->ops->copy;
-	soc_pcm_ops.silence = platform->driver->ops->silence;
-	soc_pcm_ops.ack = platform->driver->ops->ack;
-	soc_pcm_ops.page = platform->driver->ops->page;
+	if (platform->driver->ops) {
+		soc_pcm_ops.mmap = platform->driver->ops->mmap;
+		soc_pcm_ops.pointer = platform->driver->ops->pointer;
+		soc_pcm_ops.ioctl = platform->driver->ops->ioctl;
+		soc_pcm_ops.copy = platform->driver->ops->copy;
+		soc_pcm_ops.silence = platform->driver->ops->silence;
+		soc_pcm_ops.ack = platform->driver->ops->ack;
+		soc_pcm_ops.page = platform->driver->ops->page;
+	}
 
 	if (playback)
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops);
@@ -2119,10 +2141,13 @@ static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 	if (capture)
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops);
 
-	ret = platform->driver->pcm_new(rtd->card->snd_card, codec_dai, pcm);
-	if (ret < 0) {
-		printk(KERN_ERR "asoc: platform pcm constructor failed\n");
-		return ret;
+	if (platform->driver->pcm_new) {
+		ret = platform->driver->pcm_new(rtd->card->snd_card,
+						codec_dai, pcm);
+		if (ret < 0) {
+			pr_err("asoc: platform pcm constructor failed\n");
+			return ret;
+		}
 	}
 
 	pcm->private_free = platform->driver->pcm_free;
@@ -2150,6 +2175,42 @@ int snd_soc_codec_volatile_register(struct snd_soc_codec *codec,
 EXPORT_SYMBOL_GPL(snd_soc_codec_volatile_register);
 
 /**
+ * snd_soc_codec_readable_register: Report if a register is readable.
+ *
+ * @codec: CODEC to query.
+ * @reg: Register to query.
+ *
+ * Boolean function indicating if a CODEC register is readable.
+ */
+int snd_soc_codec_readable_register(struct snd_soc_codec *codec,
+				    unsigned int reg)
+{
+	if (codec->readable_register)
+		return codec->readable_register(codec, reg);
+	else
+		return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_codec_readable_register);
+
+/**
+ * snd_soc_codec_writable_register: Report if a register is writable.
+ *
+ * @codec: CODEC to query.
+ * @reg: Register to query.
+ *
+ * Boolean function indicating if a CODEC register is writable.
+ */
+int snd_soc_codec_writable_register(struct snd_soc_codec *codec,
+				    unsigned int reg)
+{
+	if (codec->writable_register)
+		return codec->writable_register(codec, reg);
+	else
+		return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_codec_writable_register);
+
+/**
  * snd_soc_new_ac97_codec - initailise AC97 device
  * @codec: audio codec
  * @ops: AC97 bus operations
@@ -2231,6 +2292,13 @@ unsigned int snd_soc_write(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(snd_soc_write);
 
+unsigned int snd_soc_bulk_write_raw(struct snd_soc_codec *codec,
+				    unsigned int reg, const void *data, size_t len)
+{
+	return codec->bulk_write_raw(codec, reg, data, len);
+}
+EXPORT_SYMBOL_GPL(snd_soc_bulk_write_raw);
+
 /**
  * snd_soc_update_bits - update codec register bits
  * @codec: audio codec
@@ -3414,7 +3482,7 @@ int snd_soc_register_dai(struct device *dev,
 
 	dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
 	if (dai == NULL)
-			return -ENOMEM;
+		return -ENOMEM;
 
 	/* create DAI component name */
 	dai->name = fmt_single_name(dev, &dai->id);
@@ -3553,7 +3621,7 @@ int snd_soc_register_platform(struct device *dev,
 
 	platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL);
 	if (platform == NULL)
-			return -ENOMEM;
+		return -ENOMEM;
 
 	/* create platform component name */
 	platform->name = fmt_single_name(dev, &platform->id);
@@ -3671,6 +3739,7 @@ int snd_soc_register_codec(struct device *dev,
 	codec->read = codec_drv->read;
 	codec->volatile_register = codec_drv->volatile_register;
 	codec->readable_register = codec_drv->readable_register;
+	codec->writable_register = codec_drv->writable_register;
 	codec->dapm.bias_level = SND_SOC_BIAS_OFF;
 	codec->dapm.dev = dev;
 	codec->dapm.codec = codec;
@@ -3705,6 +3774,8 @@ int snd_soc_register_codec(struct device *dev,
 			codec->volatile_register = snd_soc_default_volatile_register;
 		if (!codec->readable_register)
 			codec->readable_register = snd_soc_default_readable_register;
+		if (!codec->writable_register)
+			codec->writable_register = snd_soc_default_writable_register;
 	}
 
 	for (i = 0; i < num_dai; i++) {
@@ -3793,12 +3864,16 @@ static int __init snd_soc_init(void)
 		pr_warn("ASoC: Failed to create platform list debugfs file\n");
 #endif
 
+	snd_soc_util_init();
+
 	return platform_driver_register(&soc_driver);
 }
 module_init(snd_soc_init);
 
 static void __exit snd_soc_exit(void)
 {
+	snd_soc_util_exit();
+
 #ifdef CONFIG_DEBUG_FS
 	debugfs_remove_recursive(snd_soc_debugfs_root);
 #endif
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 81c4052c127c..456617e63789 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -187,7 +187,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
 	case snd_soc_dapm_mixer_named_ctl: {
 		int val;
 		struct soc_mixer_control *mc = (struct soc_mixer_control *)
-			w->kcontrols[i].private_value;
+			w->kcontrol_news[i].private_value;
 		unsigned int reg = mc->reg;
 		unsigned int shift = mc->shift;
 		int max = mc->max;
@@ -204,7 +204,8 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
 	}
 	break;
 	case snd_soc_dapm_mux: {
-		struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value;
+		struct soc_enum *e = (struct soc_enum *)
+			w->kcontrol_news[i].private_value;
 		int val, item, bitmask;
 
 		for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
@@ -220,7 +221,8 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
 	}
 	break;
 	case snd_soc_dapm_virt_mux: {
-		struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value;
+		struct soc_enum *e = (struct soc_enum *)
+			w->kcontrol_news[i].private_value;
 
 		p->connect = 0;
 		/* since a virtual mux has no backing registers to
@@ -235,7 +237,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
 	break;
 	case snd_soc_dapm_value_mux: {
 		struct soc_enum *e = (struct soc_enum *)
-			w->kcontrols[i].private_value;
+			w->kcontrol_news[i].private_value;
 		int val, item;
 
 		val = snd_soc_read(w->codec, e->reg);
@@ -310,11 +312,11 @@ static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
 
 	/* search for mixer kcontrol */
 	for (i = 0; i < dest->num_kcontrols; i++) {
-		if (!strcmp(control_name, dest->kcontrols[i].name)) {
+		if (!strcmp(control_name, dest->kcontrol_news[i].name)) {
 			list_add(&path->list, &dapm->card->paths);
 			list_add(&path->list_sink, &dest->sources);
 			list_add(&path->list_source, &src->sinks);
-			path->name = dest->kcontrols[i].name;
+			path->name = dest->kcontrol_news[i].name;
 			dapm_set_path_status(dest, path, i);
 			return 0;
 		}
@@ -322,43 +324,26 @@ static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
 	return -ENODEV;
 }
 
-/* update dapm codec register bits */
-static int dapm_update_bits(struct snd_soc_dapm_widget *widget)
+static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
+	const struct snd_kcontrol_new *kcontrol_new,
+	struct snd_kcontrol **kcontrol)
 {
-	int change, power;
-	unsigned int old, new;
-	struct snd_soc_codec *codec = widget->codec;
-	struct snd_soc_dapm_context *dapm = widget->dapm;
-	struct snd_soc_card *card = dapm->card;
-
-	/* check for valid widgets */
-	if (widget->reg < 0 || widget->id == snd_soc_dapm_input ||
-		widget->id == snd_soc_dapm_output ||
-		widget->id == snd_soc_dapm_hp ||
-		widget->id == snd_soc_dapm_mic ||
-		widget->id == snd_soc_dapm_line ||
-		widget->id == snd_soc_dapm_spk)
-		return 0;
-
-	power = widget->power;
-	if (widget->invert)
-		power = (power ? 0:1);
+	struct snd_soc_dapm_widget *w;
+	int i;
 
-	old = snd_soc_read(codec, widget->reg);
-	new = (old & ~(0x1 << widget->shift)) | (power << widget->shift);
+	*kcontrol = NULL;
 
-	change = old != new;
-	if (change) {
-		pop_dbg(dapm->dev, card->pop_time,
-			"pop test %s : %s in %d ms\n",
-			widget->name, widget->power ? "on" : "off",
-			card->pop_time);
-		pop_wait(card->pop_time);
-		snd_soc_write(codec, widget->reg, new);
+	list_for_each_entry(w, &dapm->card->widgets, list) {
+		for (i = 0; i < w->num_kcontrols; i++) {
+			if (&w->kcontrol_news[i] == kcontrol_new) {
+				if (w->kcontrols)
+					*kcontrol = w->kcontrols[i];
+				return 1;
+			}
+		}
 	}
-	dev_dbg(dapm->dev, "reg %x old %x new %x change %d\n", widget->reg,
-		old, new, change);
-	return change;
+
+	return 0;
 }
 
 /* create new dapm mixer control */
@@ -370,6 +355,8 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm,
 	struct snd_soc_dapm_path *path;
 	struct snd_card *card = dapm->card->snd_card;
 	const char *prefix;
+	struct snd_soc_dapm_widget_list *wlist;
+	size_t wlistsize;
 
 	if (dapm->codec)
 		prefix = dapm->codec->name_prefix;
@@ -388,23 +375,37 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm,
 		list_for_each_entry(path, &w->sources, list_sink) {
 
 			/* mixer/mux paths name must match control name */
-			if (path->name != (char*)w->kcontrols[i].name)
+			if (path->name != (char *)w->kcontrol_news[i].name)
 				continue;
 
+			wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
+				    sizeof(struct snd_soc_dapm_widget *),
+			wlist = kzalloc(wlistsize, GFP_KERNEL);
+			if (wlist == NULL) {
+				dev_err(dapm->dev,
+					"asoc: can't allocate widget list for %s\n",
+					w->name);
+				return -ENOMEM;
+			}
+			wlist->num_widgets = 1;
+			wlist->widgets[0] = w;
+
 			/* add dapm control with long name.
 			 * for dapm_mixer this is the concatenation of the
 			 * mixer and kcontrol name.
 			 * for dapm_mixer_named_ctl this is simply the
 			 * kcontrol name.
 			 */
-			name_len = strlen(w->kcontrols[i].name) + 1;
+			name_len = strlen(w->kcontrol_news[i].name) + 1;
 			if (w->id != snd_soc_dapm_mixer_named_ctl)
 				name_len += 1 + strlen(w->name);
 
 			path->long_name = kmalloc(name_len, GFP_KERNEL);
 
-			if (path->long_name == NULL)
+			if (path->long_name == NULL) {
+				kfree(wlist);
 				return -ENOMEM;
+			}
 
 			switch (w->id) {
 			default:
@@ -416,27 +417,30 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm,
 				 */
 				snprintf(path->long_name, name_len, "%s %s",
 					 w->name + prefix_len,
-					 w->kcontrols[i].name);
+					 w->kcontrol_news[i].name);
 				break;
 			case snd_soc_dapm_mixer_named_ctl:
 				snprintf(path->long_name, name_len, "%s",
-					 w->kcontrols[i].name);
+					 w->kcontrol_news[i].name);
 				break;
 			}
 
 			path->long_name[name_len - 1] = '\0';
 
-			path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w,
-						      path->long_name, prefix);
+			path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i],
+						      wlist, path->long_name,
+						      prefix);
 			ret = snd_ctl_add(card, path->kcontrol);
 			if (ret < 0) {
 				dev_err(dapm->dev,
 					"asoc: failed to add dapm kcontrol %s: %d\n",
 					path->long_name, ret);
+				kfree(wlist);
 				kfree(path->long_name);
 				path->long_name = NULL;
 				return ret;
 			}
+			w->kcontrols[i] = path->kcontrol;
 		}
 	}
 	return ret;
@@ -451,42 +455,80 @@ static int dapm_new_mux(struct snd_soc_dapm_context *dapm,
 	struct snd_card *card = dapm->card->snd_card;
 	const char *prefix;
 	size_t prefix_len;
-	int ret = 0;
-
-	if (!w->num_kcontrols) {
-		dev_err(dapm->dev, "asoc: mux %s has no controls\n", w->name);
+	int ret;
+	struct snd_soc_dapm_widget_list *wlist;
+	int shared, wlistentries;
+	size_t wlistsize;
+	char *name;
+
+	if (w->num_kcontrols != 1) {
+		dev_err(dapm->dev,
+			"asoc: mux %s has incorrect number of controls\n",
+			w->name);
 		return -EINVAL;
 	}
 
-	if (dapm->codec)
-		prefix = dapm->codec->name_prefix;
-	else
-		prefix = NULL;
+	shared = dapm_is_shared_kcontrol(dapm, &w->kcontrol_news[0],
+					 &kcontrol);
+	if (kcontrol) {
+		wlist = kcontrol->private_data;
+		wlistentries = wlist->num_widgets + 1;
+	} else {
+		wlist = NULL;
+		wlistentries = 1;
+	}
+	wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
+		wlistentries * sizeof(struct snd_soc_dapm_widget *),
+	wlist = krealloc(wlist, wlistsize, GFP_KERNEL);
+	if (wlist == NULL) {
+		dev_err(dapm->dev,
+			"asoc: can't allocate widget list for %s\n", w->name);
+		return -ENOMEM;
+	}
+	wlist->num_widgets = wlistentries;
+	wlist->widgets[wlistentries - 1] = w;
 
-	if (prefix)
-		prefix_len = strlen(prefix) + 1;
-	else
-		prefix_len = 0;
+	if (!kcontrol) {
+		if (dapm->codec)
+			prefix = dapm->codec->name_prefix;
+		else
+			prefix = NULL;
+
+		if (shared) {
+			name = w->kcontrol_news[0].name;
+			prefix_len = 0;
+		} else {
+			name = w->name;
+			if (prefix)
+				prefix_len = strlen(prefix) + 1;
+			else
+				prefix_len = 0;
+		}
 
-	/* The control will get a prefix from the control creation
-	 * process but we're also using the same prefix for widgets so
-	 * cut the prefix off the front of the widget name.
-	 */
-	kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name + prefix_len,
-				prefix);
-	ret = snd_ctl_add(card, kcontrol);
+		/*
+		 * The control will get a prefix from the control creation
+		 * process but we're also using the same prefix for widgets so
+		 * cut the prefix off the front of the widget name.
+		 */
+		kcontrol = snd_soc_cnew(&w->kcontrol_news[0], wlist,
+					name + prefix_len, prefix);
+		ret = snd_ctl_add(card, kcontrol);
+		if (ret < 0) {
+			dev_err(dapm->dev,
+				"asoc: failed to add kcontrol %s\n", w->name);
+			kfree(wlist);
+			return ret;
+		}
+	}
 
-	if (ret < 0)
-		goto err;
+	kcontrol->private_data = wlist;
+
+	w->kcontrols[0] = kcontrol;
 
 	list_for_each_entry(path, &w->sources, list_sink)
 		path->kcontrol = kcontrol;
 
-	return ret;
-
-err:
-	dev_err(dapm->dev, "asoc: failed to add kcontrol %s\n", w->name);
-	return ret;
+	return 0;
 }
 
 /* create new dapm volume control */
@@ -644,57 +686,6 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w,
 }
 EXPORT_SYMBOL_GPL(dapm_reg_event);
 
-/* Standard power change method, used to apply power changes to most
- * widgets.
- */
-static int dapm_generic_apply_power(struct snd_soc_dapm_widget *w)
-{
-	int ret;
-
-	/* call any power change event handlers */
-	if (w->event)
-		dev_dbg(w->dapm->dev, "power %s event for %s flags %x\n",
-			 w->power ? "on" : "off",
-			 w->name, w->event_flags);
-
-	/* power up pre event */
-	if (w->power && w->event &&
-	    (w->event_flags & SND_SOC_DAPM_PRE_PMU)) {
-		ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU);
-		if (ret < 0)
-			return ret;
-	}
-
-	/* power down pre event */
-	if (!w->power && w->event &&
-	    (w->event_flags & SND_SOC_DAPM_PRE_PMD)) {
-		ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD);
-		if (ret < 0)
-			return ret;
-	}
-
-	dapm_update_bits(w);
-
-	/* power up post event */
-	if (w->power && w->event &&
-	    (w->event_flags & SND_SOC_DAPM_POST_PMU)) {
-		ret = w->event(w,
-			       NULL, SND_SOC_DAPM_POST_PMU);
-		if (ret < 0)
-			return ret;
-	}
-
-	/* power down post event */
-	if (!w->power && w->event &&
-	    (w->event_flags & SND_SOC_DAPM_POST_PMD)) {
-		ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD);
-		if (ret < 0)
-			return ret;
-	}
-
-	return 0;
-}
-
 /* Generic check to see if a widget should be powered.
  */
 static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
@@ -981,16 +972,6 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
 					       NULL, SND_SOC_DAPM_POST_PMD);
 			break;
 
-		case snd_soc_dapm_input:
-		case snd_soc_dapm_output:
-		case snd_soc_dapm_hp:
-		case snd_soc_dapm_mic:
-		case snd_soc_dapm_line:
-		case snd_soc_dapm_spk:
-			/* No register support currently */
-			ret = dapm_generic_apply_power(w);
-			break;
-
 		default:
 			/* Queue it up for application */
 			cur_sort = sort[w->id];
@@ -1201,6 +1182,15 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
 		}
 	}
 
+	/* Force all contexts in the card to the same bias state */
+	power = 0;
+	list_for_each_entry(d, &card->dapm_list, list)
+		if (d->dev_power)
+			power = 1;
+	list_for_each_entry(d, &card->dapm_list, list)
+		d->dev_power = power;
+
+
 	/* Run all the bias changes in parallel */
 	list_for_each_entry(d, &dapm->card->dapm_list, list)
 		async_schedule_domain(dapm_pre_sequence_async, d,
@@ -1304,31 +1294,104 @@ static const struct file_operations dapm_widget_power_fops = {
 	.llseek = default_llseek,
 };
 
-void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm)
+static int dapm_bias_open_file(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
+				   size_t count, loff_t *ppos)
+{
+	struct snd_soc_dapm_context *dapm = file->private_data;
+	char *level;
+
+	switch (dapm->bias_level) {
+	case SND_SOC_BIAS_ON:
+		level = "On\n";
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		level = "Prepare\n";
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		level = "Standby\n";
+		break;
+	case SND_SOC_BIAS_OFF:
+		level = "Off\n";
+		break;
+	default:
+		BUG();
+		level = "Unknown\n";
+		break;
+	}
+
+	return simple_read_from_buffer(user_buf, count, ppos, level,
+				       strlen(level));
+}
+
+static const struct file_operations dapm_bias_fops = {
+	.open = dapm_bias_open_file,
+	.read = dapm_bias_read_file,
+	.llseek = default_llseek,
+};
+
+void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
+	struct dentry *parent)
 {
-	struct snd_soc_dapm_widget *w;
 	struct dentry *d;
 
-	if (!dapm->debugfs_dapm)
+	dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
+
+	if (!dapm->debugfs_dapm) {
+		printk(KERN_WARNING
+		       "Failed to create DAPM debugfs directory\n");
 		return;
+	}
 
-	list_for_each_entry(w, &dapm->card->widgets, list) {
-		if (!w->name || w->dapm != dapm)
-			continue;
+	d = debugfs_create_file("bias_level", 0444,
+				dapm->debugfs_dapm, dapm,
+				&dapm_bias_fops);
+	if (!d)
+		dev_warn(dapm->dev,
+			 "ASoC: Failed to create bias level debugfs file\n");
+}
 
-		d = debugfs_create_file(w->name, 0444,
-					dapm->debugfs_dapm, w,
-					&dapm_widget_power_fops);
-		if (!d)
-			dev_warn(w->dapm->dev,
-				"ASoC: Failed to create %s debugfs file\n",
-				w->name);
-	}
+static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
+{
+	struct snd_soc_dapm_context *dapm = w->dapm;
+	struct dentry *d;
+
+	if (!dapm->debugfs_dapm || !w->name)
+		return;
+
+	d = debugfs_create_file(w->name, 0444,
+				dapm->debugfs_dapm, w,
+				&dapm_widget_power_fops);
+	if (!d)
+		dev_warn(w->dapm->dev,
+			"ASoC: Failed to create %s debugfs file\n",
+			w->name);
+}
+
+static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
+{
+	debugfs_remove_recursive(dapm->debugfs_dapm);
 }
+
 #else
-void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm)
+void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
+	struct dentry *parent)
+{
+}
+
+static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
+{
+}
+
+static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
 {
 }
+
 #endif
 
 /* test and update the power status of a mux widget */
@@ -1496,32 +1559,49 @@ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
 			kfree(p->long_name);
 			kfree(p);
 		}
+		kfree(w->kcontrols);
 		kfree(w->name);
 		kfree(w);
 	}
 }
 
-static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
-				const char *pin, int status)
+static struct snd_soc_dapm_widget *dapm_find_widget(
+			struct snd_soc_dapm_context *dapm, const char *pin,
+			bool search_other_contexts)
 {
 	struct snd_soc_dapm_widget *w;
+	struct snd_soc_dapm_widget *fallback = NULL;
 
 	list_for_each_entry(w, &dapm->card->widgets, list) {
-		if (w->dapm != dapm)
-			continue;
 		if (!strcmp(w->name, pin)) {
-			dev_dbg(w->dapm->dev, "dapm: pin %s = %d\n",
-				pin, status);
-			w->connected = status;
-			/* Allow disabling of forced pins */
-			if (status == 0)
-				w->force = 0;
-			return 0;
+			if (w->dapm == dapm)
+				return w;
+			else
+				fallback = w;
 		}
 	}
 
-	dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
-	return -EINVAL;
+	if (search_other_contexts)
+		return fallback;
+
+	return NULL;
+}
+
+static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
+				const char *pin, int status)
+{
+	struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
+
+	if (!w) {
+		dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
+		return -EINVAL;
+	}
+
+	w->connected = status;
+	if (status == 0)
+		w->force = 0;
+
+	return 0;
 }
 
 /**
@@ -1627,7 +1707,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
 	}
 
 	/* connect dynamic paths */
-	switch(wsink->id) {
+	switch (wsink->id) {
 	case snd_soc_dapm_adc:
 	case snd_soc_dapm_dac:
 	case snd_soc_dapm_pga:
@@ -1650,7 +1730,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
 	case snd_soc_dapm_virt_mux:
 	case snd_soc_dapm_value_mux:
 		ret = dapm_connect_mux(dapm, wsource, wsink, path, control,
-			&wsink->kcontrols[0]);
+			&wsink->kcontrol_news[0]);
 		if (ret != 0)
 			goto err;
 		break;
@@ -1730,6 +1810,14 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
 		if (w->new)
 			continue;
 
+		if (w->num_kcontrols) {
+			w->kcontrols = kzalloc(w->num_kcontrols *
+						sizeof(struct snd_kcontrol *),
+						GFP_KERNEL);
+			if (!w->kcontrols)
+				return -ENOMEM;
+		}
+
 		switch(w->id) {
 		case snd_soc_dapm_switch:
 		case snd_soc_dapm_mixer:
@@ -1785,6 +1873,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
 		}
 
 		w->new = 1;
+
+		dapm_debugfs_add_widget(w);
 	}
 
 	dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
@@ -1804,7 +1894,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
 int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	unsigned int reg = mc->reg;
@@ -1843,7 +1934,9 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
 int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = widget->codec;
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	unsigned int reg = mc->reg;
@@ -1854,6 +1947,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
 	unsigned int val;
 	int connect, change;
 	struct snd_soc_dapm_update update;
+	int wi;
 
 	val = (ucontrol->value.integer.value[0] & mask);
 
@@ -1862,31 +1956,36 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
 	mask = mask << shift;
 	val = val << shift;
 
-	mutex_lock(&widget->codec->mutex);
-	widget->value = val;
+	if (val)
+		/* new connection */
+		connect = invert ? 0 : 1;
+	else
+		/* old connection must be powered down */
+		connect = invert ? 1 : 0;
+
+	mutex_lock(&codec->mutex);
 
 	change = snd_soc_test_bits(widget->codec, reg, mask, val);
 	if (change) {
-		if (val)
-			/* new connection */
-			connect = invert ? 0:1;
-		else
-			/* old connection must be powered down */
-			connect = invert ? 1:0;
+		for (wi = 0; wi < wlist->num_widgets; wi++) {
+			widget = wlist->widgets[wi];
 
-		update.kcontrol = kcontrol;
-		update.widget = widget;
-		update.reg = reg;
-		update.mask = mask;
-		update.val = val;
-		widget->dapm->update = &update;
+			widget->value = val;
 
-		dapm_mixer_update_power(widget, kcontrol, connect);
+			update.kcontrol = kcontrol;
+			update.widget = widget;
+			update.reg = reg;
+			update.mask = mask;
+			update.val = val;
+			widget->dapm->update = &update;
 
-		widget->dapm->update = NULL;
+			dapm_mixer_update_power(widget, kcontrol, connect);
+
+			widget->dapm->update = NULL;
+		}
 	}
 
-	mutex_unlock(&widget->codec->mutex);
+	mutex_unlock(&codec->mutex);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
@@ -1903,7 +2002,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
 int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned int val, bitmask;
 
@@ -1931,11 +2031,14 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
 int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = widget->codec;
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned int val, mux, change;
 	unsigned int mask, bitmask;
 	struct snd_soc_dapm_update update;
+	int wi;
 
 	for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
 		;
@@ -1951,22 +2054,29 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
 		mask |= (bitmask - 1) << e->shift_r;
 	}
 
-	mutex_lock(&widget->codec->mutex);
-	widget->value = val;
+	mutex_lock(&codec->mutex);
+
 	change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
+	if (change) {
+		for (wi = 0; wi < wlist->num_widgets; wi++) {
+			widget = wlist->widgets[wi];
 
-	update.kcontrol = kcontrol;
-	update.widget = widget;
-	update.reg = e->reg;
-	update.mask = mask;
-	update.val = val;
-	widget->dapm->update = &update;
+			widget->value = val;
 
-	dapm_mux_update_power(widget, kcontrol, change, mux, e);
+			update.kcontrol = kcontrol;
+			update.widget = widget;
+			update.reg = e->reg;
+			update.mask = mask;
+			update.val = val;
+			widget->dapm->update = &update;
 
-	widget->dapm->update = NULL;
+			dapm_mux_update_power(widget, kcontrol, change, mux, e);
 
-	mutex_unlock(&widget->codec->mutex);
+			widget->dapm->update = NULL;
+		}
+	}
+
+	mutex_unlock(&codec->mutex);
 	return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
@@ -1981,7 +2091,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
 int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 
 	ucontrol->value.enumerated.item[0] = widget->value;
 
@@ -1999,22 +2110,33 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt);
 int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = widget->codec;
 	struct soc_enum *e =
 		(struct soc_enum *)kcontrol->private_value;
 	int change;
 	int ret = 0;
+	int wi;
 
 	if (ucontrol->value.enumerated.item[0] >= e->max)
 		return -EINVAL;
 
-	mutex_lock(&widget->codec->mutex);
+	mutex_lock(&codec->mutex);
 
 	change = widget->value != ucontrol->value.enumerated.item[0];
-	widget->value = ucontrol->value.enumerated.item[0];
-	dapm_mux_update_power(widget, kcontrol, change, widget->value, e);
+	if (change) {
+		for (wi = 0; wi < wlist->num_widgets; wi++) {
+			widget = wlist->widgets[wi];
 
-	mutex_unlock(&widget->codec->mutex);
+			widget->value = ucontrol->value.enumerated.item[0];
+
+			dapm_mux_update_power(widget, kcontrol, change,
+					      widget->value, e);
+		}
+	}
+
+	mutex_unlock(&codec->mutex);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
@@ -2035,7 +2157,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
 int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned int reg_val, val, mux;
 
@@ -2075,11 +2198,14 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double);
 int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = widget->codec;
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned int val, mux, change;
 	unsigned int mask;
 	struct snd_soc_dapm_update update;
+	int wi;
 
 	if (ucontrol->value.enumerated.item[0] > e->max - 1)
 		return -EINVAL;
@@ -2093,22 +2219,29 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
 		mask |= e->mask << e->shift_r;
 	}
 
-	mutex_lock(&widget->codec->mutex);
-	widget->value = val;
+	mutex_lock(&codec->mutex);
+
 	change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
+	if (change) {
+		for (wi = 0; wi < wlist->num_widgets; wi++) {
+			widget = wlist->widgets[wi];
 
-	update.kcontrol = kcontrol;
-	update.widget = widget;
-	update.reg = e->reg;
-	update.mask = mask;
-	update.val = val;
-	widget->dapm->update = &update;
+			widget->value = val;
 
-	dapm_mux_update_power(widget, kcontrol, change, mux, e);
+			update.kcontrol = kcontrol;
+			update.widget = widget;
+			update.reg = e->reg;
+			update.mask = mask;
+			update.val = val;
+			widget->dapm->update = &update;
 
-	widget->dapm->update = NULL;
+			dapm_mux_update_power(widget, kcontrol, change, mux, e);
+
+			widget->dapm->update = NULL;
+		}
+	}
 
-	mutex_unlock(&widget->codec->mutex);
+	mutex_unlock(&codec->mutex);
 	return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
@@ -2346,22 +2479,18 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
 int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
 				  const char *pin)
 {
-	struct snd_soc_dapm_widget *w;
+	struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
 
-	list_for_each_entry(w, &dapm->card->widgets, list) {
-		if (w->dapm != dapm)
-			continue;
-		if (!strcmp(w->name, pin)) {
-			dev_dbg(w->dapm->dev,
-				"dapm: force enable pin %s\n", pin);
-			w->connected = 1;
-			w->force = 1;
-			return 0;
-		}
+	if (!w) {
+		dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
+		return -EINVAL;
 	}
 
-	dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
-	return -EINVAL;
+	dev_dbg(w->dapm->dev, "dapm: force enable pin %s\n", pin);
+	w->connected = 1;
+	w->force = 1;
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
 
@@ -2413,14 +2542,10 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
 int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
 				const char *pin)
 {
-	struct snd_soc_dapm_widget *w;
+	struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
 
-	list_for_each_entry(w, &dapm->card->widgets, list) {
-		if (w->dapm != dapm)
-			continue;
-		if (!strcmp(w->name, pin))
-			return w->connected;
-	}
+	if (w)
+		return w->connected;
 
 	return 0;
 }
@@ -2440,19 +2565,16 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
 int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
 				const char *pin)
 {
-	struct snd_soc_dapm_widget *w;
+	struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false);
 
-	list_for_each_entry(w, &dapm->card->widgets, list) {
-		if (w->dapm != dapm)
-			continue;
-		if (!strcmp(w->name, pin)) {
-			w->ignore_suspend = 1;
-			return 0;
-		}
+	if (!w) {
+		dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
+		return -EINVAL;
 	}
 
-	dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
-	return -EINVAL;
+	w->ignore_suspend = 1;
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
 
@@ -2465,6 +2587,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
 void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
 {
 	snd_soc_dapm_sys_remove(dapm->dev);
+	dapm_debugfs_cleanup(dapm);
 	dapm_free_widgets(dapm);
 	list_del(&dapm->list);
 }
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index fc017c0a7b5d..7c17b98d5846 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -325,7 +325,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
 					      gpio_handler,
 					      IRQF_TRIGGER_RISING |
 					      IRQF_TRIGGER_FALLING,
-					      jack->codec->dev->driver->name,
+					      gpios[i].name,
 					      &gpios[i]);
 		if (ret)
 			goto err;
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c
index 3f45e6a439bf..ec921ec99c26 100644
--- a/sound/soc/soc-utils.c
+++ b/sound/soc/soc-utils.c
@@ -13,6 +13,7 @@
  *  option) any later version.
  */
 
+#include <linux/platform_device.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -55,3 +56,55 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params)
 		return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk);
+
+static struct snd_soc_platform_driver dummy_platform;
+
+static __devinit int snd_soc_dummy_probe(struct platform_device *pdev)
+{
+	return snd_soc_register_platform(&pdev->dev, &dummy_platform);
+}
+
+static __devexit int snd_soc_dummy_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+
+	return 0;
+}
+
+static struct platform_driver soc_dummy_driver = {
+	.driver = {
+		.name = "snd-soc-dummy",
+		.owner = THIS_MODULE,
+	},
+	.probe = snd_soc_dummy_probe,
+	.remove = __devexit_p(snd_soc_dummy_remove),
+};
+
+static struct platform_device *soc_dummy_dev;
+
+int __init snd_soc_util_init(void)
+{
+	int ret;
+
+	soc_dummy_dev = platform_device_alloc("snd-soc-dummy", -1);
+	if (!soc_dummy_dev)
+		return -ENOMEM;
+
+	ret = platform_device_add(soc_dummy_dev);
+	if (ret != 0) {
+		platform_device_put(soc_dummy_dev);
+		return ret;
+	}
+
+	ret = platform_driver_register(&soc_dummy_driver);
+	if (ret != 0)
+		platform_device_unregister(soc_dummy_dev);
+
+	return ret;
+}
+
+void __exit snd_soc_util_exit(void)
+{
+	platform_device_unregister(soc_dummy_dev);
+	platform_driver_unregister(&soc_dummy_driver);
+}
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 66b504f06c23..035d39a4beb4 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -1,26 +1,40 @@
-config SND_TEGRA_SOC
+config SND_SOC_TEGRA
 	tristate "SoC Audio for the Tegra System-on-Chip"
 	depends on ARCH_TEGRA && TEGRA_SYSTEM_DMA
-	default m
 	help
 	  Say Y or M here if you want support for SoC audio on Tegra.
 
-config SND_TEGRA_SOC_I2S
+config SND_SOC_TEGRA_I2S
 	tristate
-	depends on SND_TEGRA_SOC
-	default m
+	depends on SND_SOC_TEGRA
 	help
 	  Say Y or M if you want to add support for codecs attached to the
 	  Tegra I2S interface. You will also need to select the individual
 	  machine drivers to support below.
 
-config SND_TEGRA_SOC_HARMONY
-	tristate "SoC Audio support for Tegra Harmony reference board"
-	depends on SND_TEGRA_SOC && MACH_HARMONY && I2C
-	default m
-	select SND_TEGRA_SOC_I2S
+config MACH_HAS_SND_SOC_TEGRA_WM8903
+	bool
+	help
+	  Machines that use the SND_SOC_TEGRA_WM8903 driver should select
+	  this config option, in order to allow the user to enable
+	  SND_SOC_TEGRA_WM8903.
+
+config SND_SOC_TEGRA_WM8903
+	tristate "SoC Audio support for Tegra boards using a WM8903 codec"
+	depends on SND_SOC_TEGRA && I2C
+	depends on MACH_HAS_SND_SOC_TEGRA_WM8903
+	select SND_SOC_TEGRA_I2S
 	select SND_SOC_WM8903
 	help
-	  Say Y or M here if you want to add support for SoC audio on the
-	  Tegra Harmony reference board.
+	  Say Y or M here if you want to add support for SoC audio on Tegra
+	  boards using the WM8093 codec. Currently, the supported boards are
+	  Harmony, Ventana, Seaboard, Kaen, and Aebl.
 
+config SND_SOC_TEGRA_TRIMSLICE
+	tristate "SoC Audio support for TrimSlice board"
+	depends on SND_SOC_TEGRA && MACH_TRIMSLICE && I2C
+	select SND_SOC_TEGRA_I2S
+	select SND_SOC_TLV320AIC23
+	help
+	  Say Y or M here if you want to add support for SoC audio on the
+	  TrimSlice platform.
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index fd183d3ab4f1..fa6574d92a31 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -4,12 +4,14 @@ snd-soc-tegra-pcm-objs := tegra_pcm.o
 snd-soc-tegra-i2s-objs := tegra_i2s.o
 snd-soc-tegra-utils-objs += tegra_asoc_utils.o
 
-obj-$(CONFIG_SND_TEGRA_SOC) += snd-soc-tegra-utils.o
-obj-$(CONFIG_SND_TEGRA_SOC) += snd-soc-tegra-das.o
-obj-$(CONFIG_SND_TEGRA_SOC) += snd-soc-tegra-pcm.o
-obj-$(CONFIG_SND_TEGRA_SOC_I2S) += snd-soc-tegra-i2s.o
+obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
+obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-das.o
+obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
+obj-$(CONFIG_SND_SOC_TEGRA_I2S) += snd-soc-tegra-i2s.o
 
 # Tegra machine Support
-snd-soc-tegra-harmony-objs := harmony.o
+snd-soc-tegra-wm8903-objs := tegra_wm8903.o
+snd-soc-tegra-trimslice-objs := trimslice.o
 
-obj-$(CONFIG_SND_TEGRA_SOC_HARMONY) += snd-soc-tegra-harmony.o
+obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o
+obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o
diff --git a/sound/soc/tegra/harmony.c b/sound/soc/tegra/harmony.c
deleted file mode 100644
index 556a57133925..000000000000
--- a/sound/soc/tegra/harmony.c
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
- * harmony.c - Harmony machine ASoC driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010-2011 - NVIDIA, Inc.
- *
- * Based on code copyright/by:
- *
- * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd.
- *
- * Copyright 2007 Wolfson Microelectronics PLC.
- * Author: Graeme Gregory
- *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.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 <asm/mach-types.h>
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/gpio.h>
-
-#include <mach/harmony_audio.h>
-
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include "../codecs/wm8903.h"
-
-#include "tegra_das.h"
-#include "tegra_i2s.h"
-#include "tegra_pcm.h"
-#include "tegra_asoc_utils.h"
-
-#define DRV_NAME "tegra-snd-harmony"
-
-#define GPIO_SPKR_EN    BIT(0)
-#define GPIO_INT_MIC_EN BIT(1)
-#define GPIO_EXT_MIC_EN BIT(2)
-
-struct tegra_harmony {
-	struct tegra_asoc_utils_data util_data;
-	struct harmony_audio_platform_data *pdata;
-	int gpio_requested;
-};
-
-static int harmony_asoc_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->codec_dai;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_codec *codec = rtd->codec;
-	struct snd_soc_card *card = codec->card;
-	struct tegra_harmony *harmony = snd_soc_card_get_drvdata(card);
-	int srate, mclk, mclk_change;
-	int err;
-
-	srate = params_rate(params);
-	switch (srate) {
-	case 64000:
-	case 88200:
-	case 96000:
-		mclk = 128 * srate;
-		break;
-	default:
-		mclk = 256 * srate;
-		break;
-	}
-	/* FIXME: Codec only requires >= 3MHz if OSR==0 */
-	while (mclk < 6000000)
-		mclk *= 2;
-
-	err = tegra_asoc_utils_set_rate(&harmony->util_data, srate, mclk,
-					&mclk_change);
-	if (err < 0) {
-		dev_err(card->dev, "Can't configure clocks\n");
-		return err;
-	}
-
-	err = snd_soc_dai_set_fmt(codec_dai,
-					SND_SOC_DAIFMT_I2S |
-					SND_SOC_DAIFMT_NB_NF |
-					SND_SOC_DAIFMT_CBS_CFS);
-	if (err < 0) {
-		dev_err(card->dev, "codec_dai fmt not set\n");
-		return err;
-	}
-
-	err = snd_soc_dai_set_fmt(cpu_dai,
-					SND_SOC_DAIFMT_I2S |
-					SND_SOC_DAIFMT_NB_NF |
-					SND_SOC_DAIFMT_CBS_CFS);
-	if (err < 0) {
-		dev_err(card->dev, "cpu_dai fmt not set\n");
-		return err;
-	}
-
-	if (mclk_change) {
-		err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
-					     SND_SOC_CLOCK_IN);
-		if (err < 0) {
-			dev_err(card->dev, "codec_dai clock not set\n");
-			return err;
-		}
-	}
-
-	return 0;
-}
-
-static struct snd_soc_ops harmony_asoc_ops = {
-	.hw_params = harmony_asoc_hw_params,
-};
-
-static struct snd_soc_jack harmony_hp_jack;
-
-static struct snd_soc_jack_pin harmony_hp_jack_pins[] = {
-	{
-		.pin = "Headphone Jack",
-		.mask = SND_JACK_HEADPHONE,
-	},
-};
-
-static struct snd_soc_jack_gpio harmony_hp_jack_gpios[] = {
-	{
-		.name = "headphone detect",
-		.report = SND_JACK_HEADPHONE,
-		.debounce_time = 150,
-		.invert = 1,
-	}
-};
-
-static struct snd_soc_jack harmony_mic_jack;
-
-static struct snd_soc_jack_pin harmony_mic_jack_pins[] = {
-	{
-		.pin = "Mic Jack",
-		.mask = SND_JACK_MICROPHONE,
-	},
-};
-
-static int harmony_event_int_spk(struct snd_soc_dapm_widget *w,
-					struct snd_kcontrol *k, int event)
-{
-	struct snd_soc_codec *codec = w->codec;
-	struct snd_soc_card *card = codec->card;
-	struct tegra_harmony *harmony = snd_soc_card_get_drvdata(card);
-	struct harmony_audio_platform_data *pdata = harmony->pdata;
-
-	gpio_set_value_cansleep(pdata->gpio_spkr_en,
-				SND_SOC_DAPM_EVENT_ON(event));
-
-	return 0;
-}
-
-static const struct snd_soc_dapm_widget harmony_dapm_widgets[] = {
-	SND_SOC_DAPM_SPK("Int Spk", harmony_event_int_spk),
-	SND_SOC_DAPM_HP("Headphone Jack", NULL),
-	SND_SOC_DAPM_MIC("Mic Jack", NULL),
-};
-
-static const struct snd_soc_dapm_route harmony_audio_map[] = {
-	{"Headphone Jack", NULL, "HPOUTR"},
-	{"Headphone Jack", NULL, "HPOUTL"},
-	{"Int Spk", NULL, "ROP"},
-	{"Int Spk", NULL, "RON"},
-	{"Int Spk", NULL, "LOP"},
-	{"Int Spk", NULL, "LON"},
-	{"Mic Bias", NULL, "Mic Jack"},
-	{"IN1L", NULL, "Mic Bias"},
-};
-
-static const struct snd_kcontrol_new harmony_controls[] = {
-	SOC_DAPM_PIN_SWITCH("Int Spk"),
-};
-
-static int harmony_asoc_init(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_soc_codec *codec = rtd->codec;
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-	struct snd_soc_card *card = codec->card;
-	struct tegra_harmony *harmony = snd_soc_card_get_drvdata(card);
-	struct harmony_audio_platform_data *pdata = harmony->pdata;
-	int ret;
-
-	ret = gpio_request(pdata->gpio_spkr_en, "spkr_en");
-	if (ret) {
-		dev_err(card->dev, "cannot get spkr_en gpio\n");
-		return ret;
-	}
-	harmony->gpio_requested |= GPIO_SPKR_EN;
-
-	gpio_direction_output(pdata->gpio_spkr_en, 0);
-
-	ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en");
-	if (ret) {
-		dev_err(card->dev, "cannot get int_mic_en gpio\n");
-		return ret;
-	}
-	harmony->gpio_requested |= GPIO_INT_MIC_EN;
-
-	/* Disable int mic; enable signal is active-high */
-	gpio_direction_output(pdata->gpio_int_mic_en, 0);
-
-	ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en");
-	if (ret) {
-		dev_err(card->dev, "cannot get ext_mic_en gpio\n");
-		return ret;
-	}
-	harmony->gpio_requested |= GPIO_EXT_MIC_EN;
-
-	/* Enable ext mic; enable signal is active-low */
-	gpio_direction_output(pdata->gpio_ext_mic_en, 0);
-
-	ret = snd_soc_add_controls(codec, harmony_controls,
-				   ARRAY_SIZE(harmony_controls));
-	if (ret < 0)
-		return ret;
-
-	snd_soc_dapm_new_controls(dapm, harmony_dapm_widgets,
-					ARRAY_SIZE(harmony_dapm_widgets));
-
-	snd_soc_dapm_add_routes(dapm, harmony_audio_map,
-				ARRAY_SIZE(harmony_audio_map));
-
-	harmony_hp_jack_gpios[0].gpio = pdata->gpio_hp_det;
-	snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
-			 &harmony_hp_jack);
-	snd_soc_jack_add_pins(&harmony_hp_jack,
-			      ARRAY_SIZE(harmony_hp_jack_pins),
-			      harmony_hp_jack_pins);
-	snd_soc_jack_add_gpios(&harmony_hp_jack,
-			       ARRAY_SIZE(harmony_hp_jack_gpios),
-			       harmony_hp_jack_gpios);
-
-	snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
-			 &harmony_mic_jack);
-	snd_soc_jack_add_pins(&harmony_mic_jack,
-			      ARRAY_SIZE(harmony_mic_jack_pins),
-			      harmony_mic_jack_pins);
-	wm8903_mic_detect(codec, &harmony_mic_jack, SND_JACK_MICROPHONE, 0);
-
-	snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
-
-	snd_soc_dapm_nc_pin(dapm, "IN3L");
-	snd_soc_dapm_nc_pin(dapm, "IN3R");
-	snd_soc_dapm_nc_pin(dapm, "LINEOUTL");
-	snd_soc_dapm_nc_pin(dapm, "LINEOUTR");
-
-	snd_soc_dapm_sync(dapm);
-
-	return 0;
-}
-
-static struct snd_soc_dai_link harmony_wm8903_dai = {
-	.name = "WM8903",
-	.stream_name = "WM8903 PCM",
-	.codec_name = "wm8903.0-001a",
-	.platform_name = "tegra-pcm-audio",
-	.cpu_dai_name = "tegra-i2s.0",
-	.codec_dai_name = "wm8903-hifi",
-	.init = harmony_asoc_init,
-	.ops = &harmony_asoc_ops,
-};
-
-static struct snd_soc_card snd_soc_harmony = {
-	.name = "tegra-harmony",
-	.dai_link = &harmony_wm8903_dai,
-	.num_links = 1,
-};
-
-static __devinit int tegra_snd_harmony_probe(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = &snd_soc_harmony;
-	struct tegra_harmony *harmony;
-	struct harmony_audio_platform_data *pdata;
-	int ret;
-
-	if (!machine_is_harmony()) {
-		dev_err(&pdev->dev, "Not running on Tegra Harmony!\n");
-		return -ENODEV;
-	}
-
-	pdata = pdev->dev.platform_data;
-	if (!pdata) {
-		dev_err(&pdev->dev, "no platform data supplied\n");
-		return -EINVAL;
-	}
-
-	harmony = kzalloc(sizeof(struct tegra_harmony), GFP_KERNEL);
-	if (!harmony) {
-		dev_err(&pdev->dev, "Can't allocate tegra_harmony\n");
-		return -ENOMEM;
-	}
-
-	harmony->pdata = pdata;
-
-	ret = tegra_asoc_utils_init(&harmony->util_data, &pdev->dev);
-	if (ret)
-		goto err_free_harmony;
-
-	card->dev = &pdev->dev;
-	platform_set_drvdata(pdev, card);
-	snd_soc_card_set_drvdata(card, harmony);
-
-	ret = snd_soc_register_card(card);
-	if (ret) {
-		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-			ret);
-		goto err_clear_drvdata;
-	}
-
-	return 0;
-
-err_clear_drvdata:
-	snd_soc_card_set_drvdata(card, NULL);
-	platform_set_drvdata(pdev, NULL);
-	card->dev = NULL;
-	tegra_asoc_utils_fini(&harmony->util_data);
-err_free_harmony:
-	kfree(harmony);
-	return ret;
-}
-
-static int __devexit tegra_snd_harmony_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-	struct tegra_harmony *harmony = snd_soc_card_get_drvdata(card);
-	struct harmony_audio_platform_data *pdata = harmony->pdata;
-
-	snd_soc_unregister_card(card);
-
-	snd_soc_card_set_drvdata(card, NULL);
-	platform_set_drvdata(pdev, NULL);
-	card->dev = NULL;
-
-	tegra_asoc_utils_fini(&harmony->util_data);
-
-	if (harmony->gpio_requested & GPIO_EXT_MIC_EN)
-		gpio_free(pdata->gpio_ext_mic_en);
-	if (harmony->gpio_requested & GPIO_INT_MIC_EN)
-		gpio_free(pdata->gpio_int_mic_en);
-	if (harmony->gpio_requested & GPIO_SPKR_EN)
-		gpio_free(pdata->gpio_spkr_en);
-
-	kfree(harmony);
-
-	return 0;
-}
-
-static struct platform_driver tegra_snd_harmony_driver = {
-	.driver = {
-		.name = DRV_NAME,
-		.owner = THIS_MODULE,
-		.pm = &snd_soc_pm_ops,
-	},
-	.probe = tegra_snd_harmony_probe,
-	.remove = __devexit_p(tegra_snd_harmony_remove),
-};
-
-static int __init snd_tegra_harmony_init(void)
-{
-	return platform_driver_register(&tegra_snd_harmony_driver);
-}
-module_init(snd_tegra_harmony_init);
-
-static void __exit snd_tegra_harmony_exit(void)
-{
-	platform_driver_unregister(&tegra_snd_harmony_driver);
-}
-module_exit(snd_tegra_harmony_exit);
-
-MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
-MODULE_DESCRIPTION("Harmony machine ASoC driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c
index 52f0a3f9ce40..dfa85cbb05c8 100644
--- a/sound/soc/tegra/tegra_asoc_utils.c
+++ b/sound/soc/tegra/tegra_asoc_utils.c
@@ -28,9 +28,10 @@
 #include "tegra_asoc_utils.h"
 
 int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
-			      int mclk, int *mclk_change)
+			      int mclk)
 {
 	int new_baseclock;
+	bool clk_change;
 	int err;
 
 	switch (srate) {
@@ -52,10 +53,10 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
 		return -EINVAL;
 	}
 
-	*mclk_change = ((new_baseclock != data->set_baseclock) ||
+	clk_change = ((new_baseclock != data->set_baseclock) ||
 			(mclk != data->set_mclk));
-	if (!*mclk_change)
-	    return 0;
+	if (!clk_change)
+		return 0;
 
 	data->set_baseclock = 0;
 	data->set_mclk = 0;
diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h
index bbba7afdfc2c..4818195da25c 100644
--- a/sound/soc/tegra/tegra_asoc_utils.h
+++ b/sound/soc/tegra/tegra_asoc_utils.h
@@ -36,7 +36,7 @@ struct tegra_asoc_utils_data {
 };
 
 int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
-			      int mclk, int *mclk_change);
+			      int mclk);
 int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
 			  struct device *dev);
 void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data);
diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c
index 4f5e2c90b020..6b817e20548c 100644
--- a/sound/soc/tegra/tegra_i2s.c
+++ b/sound/soc/tegra/tegra_i2s.c
@@ -114,7 +114,7 @@ static void tegra_i2s_debug_remove(struct tegra_i2s *i2s)
 		debugfs_remove(i2s->debug);
 }
 #else
-static inline void tegra_i2s_debug_add(struct tegra_i2s *i2s)
+static inline void tegra_i2s_debug_add(struct tegra_i2s *i2s, int id)
 {
 }
 
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
new file mode 100644
index 000000000000..0d6738a8b29a
--- /dev/null
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -0,0 +1,475 @@
+/*
+ * tegra_wm8903.c - Tegra machine ASoC driver for boards using WM8903 codec.
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010-2011 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ *
+ * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd.
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.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 <asm/mach-types.h>
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+
+#include <mach/tegra_wm8903_pdata.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "../codecs/wm8903.h"
+
+#include "tegra_das.h"
+#include "tegra_i2s.h"
+#include "tegra_pcm.h"
+#include "tegra_asoc_utils.h"
+
+#define DRV_NAME "tegra-snd-wm8903"
+
+#define GPIO_SPKR_EN    BIT(0)
+#define GPIO_HP_MUTE    BIT(1)
+#define GPIO_INT_MIC_EN BIT(2)
+#define GPIO_EXT_MIC_EN BIT(3)
+
+struct tegra_wm8903 {
+	struct tegra_asoc_utils_data util_data;
+	struct tegra_wm8903_platform_data *pdata;
+	int gpio_requested;
+};
+
+static int tegra_wm8903_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->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_card *card = codec->card;
+	struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
+	int srate, mclk;
+	int err;
+
+	srate = params_rate(params);
+	switch (srate) {
+	case 64000:
+	case 88200:
+	case 96000:
+		mclk = 128 * srate;
+		break;
+	default:
+		mclk = 256 * srate;
+		break;
+	}
+	/* FIXME: Codec only requires >= 3MHz if OSR==0 */
+	while (mclk < 6000000)
+		mclk *= 2;
+
+	err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
+	if (err < 0) {
+		dev_err(card->dev, "Can't configure clocks\n");
+		return err;
+	}
+
+	err = snd_soc_dai_set_fmt(codec_dai,
+					SND_SOC_DAIFMT_I2S |
+					SND_SOC_DAIFMT_NB_NF |
+					SND_SOC_DAIFMT_CBS_CFS);
+	if (err < 0) {
+		dev_err(card->dev, "codec_dai fmt not set\n");
+		return err;
+	}
+
+	err = snd_soc_dai_set_fmt(cpu_dai,
+					SND_SOC_DAIFMT_I2S |
+					SND_SOC_DAIFMT_NB_NF |
+					SND_SOC_DAIFMT_CBS_CFS);
+	if (err < 0) {
+		dev_err(card->dev, "cpu_dai fmt not set\n");
+		return err;
+	}
+
+	err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+					SND_SOC_CLOCK_IN);
+	if (err < 0) {
+		dev_err(card->dev, "codec_dai clock not set\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_ops tegra_wm8903_ops = {
+	.hw_params = tegra_wm8903_hw_params,
+};
+
+static struct snd_soc_jack tegra_wm8903_hp_jack;
+
+static struct snd_soc_jack_pin tegra_wm8903_hp_jack_pins[] = {
+	{
+		.pin = "Headphone Jack",
+		.mask = SND_JACK_HEADPHONE,
+	},
+};
+
+static struct snd_soc_jack_gpio tegra_wm8903_hp_jack_gpio = {
+	.name = "headphone detect",
+	.report = SND_JACK_HEADPHONE,
+	.debounce_time = 150,
+	.invert = 1,
+};
+
+static struct snd_soc_jack tegra_wm8903_mic_jack;
+
+static struct snd_soc_jack_pin tegra_wm8903_mic_jack_pins[] = {
+	{
+		.pin = "Mic Jack",
+		.mask = SND_JACK_MICROPHONE,
+	},
+};
+
+static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w,
+					struct snd_kcontrol *k, int event)
+{
+	struct snd_soc_dapm_context *dapm = w->dapm;
+	struct snd_soc_card *card = dapm->card;
+	struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
+	struct tegra_wm8903_platform_data *pdata = machine->pdata;
+
+	if (!(machine->gpio_requested & GPIO_SPKR_EN))
+		return 0;
+
+	gpio_set_value_cansleep(pdata->gpio_spkr_en,
+				SND_SOC_DAPM_EVENT_ON(event));
+
+	return 0;
+}
+
+static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w,
+					struct snd_kcontrol *k, int event)
+{
+	struct snd_soc_dapm_context *dapm = w->dapm;
+	struct snd_soc_card *card = dapm->card;
+	struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
+	struct tegra_wm8903_platform_data *pdata = machine->pdata;
+
+	if (!(machine->gpio_requested & GPIO_HP_MUTE))
+		return 0;
+
+	gpio_set_value_cansleep(pdata->gpio_hp_mute,
+				!SND_SOC_DAPM_EVENT_ON(event));
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget tegra_wm8903_dapm_widgets[] = {
+	SND_SOC_DAPM_SPK("Int Spk", tegra_wm8903_event_int_spk),
+	SND_SOC_DAPM_HP("Headphone Jack", tegra_wm8903_event_hp),
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route harmony_audio_map[] = {
+	{"Headphone Jack", NULL, "HPOUTR"},
+	{"Headphone Jack", NULL, "HPOUTL"},
+	{"Int Spk", NULL, "ROP"},
+	{"Int Spk", NULL, "RON"},
+	{"Int Spk", NULL, "LOP"},
+	{"Int Spk", NULL, "LON"},
+	{"Mic Bias", NULL, "Mic Jack"},
+	{"IN1L", NULL, "Mic Bias"},
+};
+
+static const struct snd_soc_dapm_route seaboard_audio_map[] = {
+	{"Headphone Jack", NULL, "HPOUTR"},
+	{"Headphone Jack", NULL, "HPOUTL"},
+	{"Int Spk", NULL, "ROP"},
+	{"Int Spk", NULL, "RON"},
+	{"Int Spk", NULL, "LOP"},
+	{"Int Spk", NULL, "LON"},
+	{"Mic Bias", NULL, "Mic Jack"},
+	{"IN1R", NULL, "Mic Bias"},
+};
+
+static const struct snd_soc_dapm_route kaen_audio_map[] = {
+	{"Headphone Jack", NULL, "HPOUTR"},
+	{"Headphone Jack", NULL, "HPOUTL"},
+	{"Int Spk", NULL, "ROP"},
+	{"Int Spk", NULL, "RON"},
+	{"Int Spk", NULL, "LOP"},
+	{"Int Spk", NULL, "LON"},
+	{"Mic Bias", NULL, "Mic Jack"},
+	{"IN2R", NULL, "Mic Bias"},
+};
+
+static const struct snd_soc_dapm_route aebl_audio_map[] = {
+	{"Headphone Jack", NULL, "HPOUTR"},
+	{"Headphone Jack", NULL, "HPOUTL"},
+	{"Int Spk", NULL, "LINEOUTR"},
+	{"Int Spk", NULL, "LINEOUTL"},
+	{"Mic Bias", NULL, "Mic Jack"},
+	{"IN1R", NULL, "Mic Bias"},
+};
+
+static const struct snd_kcontrol_new tegra_wm8903_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Int Spk"),
+};
+
+static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_card *card = codec->card;
+	struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
+	struct tegra_wm8903_platform_data *pdata = machine->pdata;
+	int ret;
+
+	if (gpio_is_valid(pdata->gpio_spkr_en)) {
+		ret = gpio_request(pdata->gpio_spkr_en, "spkr_en");
+		if (ret) {
+			dev_err(card->dev, "cannot get spkr_en gpio\n");
+			return ret;
+		}
+		machine->gpio_requested |= GPIO_SPKR_EN;
+
+		gpio_direction_output(pdata->gpio_spkr_en, 0);
+	}
+
+	if (gpio_is_valid(pdata->gpio_hp_mute)) {
+		ret = gpio_request(pdata->gpio_hp_mute, "hp_mute");
+		if (ret) {
+			dev_err(card->dev, "cannot get hp_mute gpio\n");
+			return ret;
+		}
+		machine->gpio_requested |= GPIO_HP_MUTE;
+
+		gpio_direction_output(pdata->gpio_hp_mute, 0);
+	}
+
+	if (gpio_is_valid(pdata->gpio_int_mic_en)) {
+		ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en");
+		if (ret) {
+			dev_err(card->dev, "cannot get int_mic_en gpio\n");
+			return ret;
+		}
+		machine->gpio_requested |= GPIO_INT_MIC_EN;
+
+		/* Disable int mic; enable signal is active-high */
+		gpio_direction_output(pdata->gpio_int_mic_en, 0);
+	}
+
+	if (gpio_is_valid(pdata->gpio_ext_mic_en)) {
+		ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en");
+		if (ret) {
+			dev_err(card->dev, "cannot get ext_mic_en gpio\n");
+			return ret;
+		}
+		machine->gpio_requested |= GPIO_EXT_MIC_EN;
+
+		/* Enable ext mic; enable signal is active-low */
+		gpio_direction_output(pdata->gpio_ext_mic_en, 0);
+	}
+
+	if (gpio_is_valid(pdata->gpio_hp_det)) {
+		tegra_wm8903_hp_jack_gpio.gpio = pdata->gpio_hp_det;
+		snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
+				&tegra_wm8903_hp_jack);
+		snd_soc_jack_add_pins(&tegra_wm8903_hp_jack,
+					ARRAY_SIZE(tegra_wm8903_hp_jack_pins),
+					tegra_wm8903_hp_jack_pins);
+		snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack,
+					1,
+					&tegra_wm8903_hp_jack_gpio);
+	}
+
+	snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
+			 &tegra_wm8903_mic_jack);
+	snd_soc_jack_add_pins(&tegra_wm8903_mic_jack,
+			      ARRAY_SIZE(tegra_wm8903_mic_jack_pins),
+			      tegra_wm8903_mic_jack_pins);
+	wm8903_mic_detect(codec, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE,
+				0);
+
+	snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
+
+	/* FIXME: Calculate automatically based on DAPM routes? */
+	if (!machine_is_harmony() && !machine_is_ventana())
+		snd_soc_dapm_nc_pin(dapm, "IN1L");
+	if (!machine_is_seaboard() && !machine_is_aebl())
+		snd_soc_dapm_nc_pin(dapm, "IN1R");
+	snd_soc_dapm_nc_pin(dapm, "IN2L");
+	if (!machine_is_kaen())
+		snd_soc_dapm_nc_pin(dapm, "IN2R");
+	snd_soc_dapm_nc_pin(dapm, "IN3L");
+	snd_soc_dapm_nc_pin(dapm, "IN3R");
+
+	if (machine_is_aebl()) {
+		snd_soc_dapm_nc_pin(dapm, "LON");
+		snd_soc_dapm_nc_pin(dapm, "RON");
+		snd_soc_dapm_nc_pin(dapm, "ROP");
+		snd_soc_dapm_nc_pin(dapm, "LOP");
+	} else {
+		snd_soc_dapm_nc_pin(dapm, "LINEOUTR");
+		snd_soc_dapm_nc_pin(dapm, "LINEOUTL");
+	}
+
+	snd_soc_dapm_sync(dapm);
+
+	return 0;
+}
+
+static struct snd_soc_dai_link tegra_wm8903_dai = {
+	.name = "WM8903",
+	.stream_name = "WM8903 PCM",
+	.codec_name = "wm8903.0-001a",
+	.platform_name = "tegra-pcm-audio",
+	.cpu_dai_name = "tegra-i2s.0",
+	.codec_dai_name = "wm8903-hifi",
+	.init = tegra_wm8903_init,
+	.ops = &tegra_wm8903_ops,
+};
+
+static struct snd_soc_card snd_soc_tegra_wm8903 = {
+	.name = "tegra-wm8903",
+	.dai_link = &tegra_wm8903_dai,
+	.num_links = 1,
+
+	.controls = tegra_wm8903_controls,
+	.num_controls = ARRAY_SIZE(tegra_wm8903_controls),
+	.dapm_widgets = tegra_wm8903_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tegra_wm8903_dapm_widgets),
+};
+
+static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &snd_soc_tegra_wm8903;
+	struct tegra_wm8903 *machine;
+	struct tegra_wm8903_platform_data *pdata;
+	int ret;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev, "No platform data supplied\n");
+		return -EINVAL;
+	}
+
+	machine = kzalloc(sizeof(struct tegra_wm8903), GFP_KERNEL);
+	if (!machine) {
+		dev_err(&pdev->dev, "Can't allocate tegra_wm8903 struct\n");
+		return -ENOMEM;
+	}
+
+	machine->pdata = pdata;
+
+	ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+	if (ret)
+		goto err_free_machine;
+
+	card->dev = &pdev->dev;
+	platform_set_drvdata(pdev, card);
+	snd_soc_card_set_drvdata(card, machine);
+
+	if (machine_is_harmony() || machine_is_ventana()) {
+		card->dapm_routes = harmony_audio_map;
+		card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map);
+	} else if (machine_is_seaboard()) {
+		card->dapm_routes = seaboard_audio_map;
+		card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map);
+	} else if (machine_is_kaen()) {
+		card->dapm_routes = kaen_audio_map;
+		card->num_dapm_routes = ARRAY_SIZE(kaen_audio_map);
+	} else {
+		card->dapm_routes = aebl_audio_map;
+		card->num_dapm_routes = ARRAY_SIZE(aebl_audio_map);
+	}
+
+	ret = snd_soc_register_card(card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+			ret);
+		goto err_fini_utils;
+	}
+
+	return 0;
+
+err_fini_utils:
+	tegra_asoc_utils_fini(&machine->util_data);
+err_free_machine:
+	kfree(machine);
+	return ret;
+}
+
+static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
+	struct tegra_wm8903_platform_data *pdata = machine->pdata;
+
+	snd_soc_unregister_card(card);
+
+	tegra_asoc_utils_fini(&machine->util_data);
+
+	if (machine->gpio_requested & GPIO_EXT_MIC_EN)
+		gpio_free(pdata->gpio_ext_mic_en);
+	if (machine->gpio_requested & GPIO_INT_MIC_EN)
+		gpio_free(pdata->gpio_int_mic_en);
+	if (machine->gpio_requested & GPIO_HP_MUTE)
+		gpio_free(pdata->gpio_hp_mute);
+	if (machine->gpio_requested & GPIO_SPKR_EN)
+		gpio_free(pdata->gpio_spkr_en);
+
+	kfree(machine);
+
+	return 0;
+}
+
+static struct platform_driver tegra_wm8903_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.pm = &snd_soc_pm_ops,
+	},
+	.probe = tegra_wm8903_driver_probe,
+	.remove = __devexit_p(tegra_wm8903_driver_remove),
+};
+
+static int __init tegra_wm8903_modinit(void)
+{
+	return platform_driver_register(&tegra_wm8903_driver);
+}
+module_init(tegra_wm8903_modinit);
+
+static void __exit tegra_wm8903_modexit(void)
+{
+	platform_driver_unregister(&tegra_wm8903_driver);
+}
+module_exit(tegra_wm8903_modexit);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra+WM8903 machine ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c
new file mode 100644
index 000000000000..8fc07e9adf2e
--- /dev/null
+++ b/sound/soc/tegra/trimslice.c
@@ -0,0 +1,228 @@
+/*
+ * trimslice.c - TrimSlice machine ASoC driver
+ *
+ * Copyright (C) 2011 - CompuLab, Ltd.
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * Based on code copyright/by:
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010-2011 - NVIDIA, Inc.
+ *
+ * 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 <asm/mach-types.h>
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "../codecs/tlv320aic23.h"
+
+#include "tegra_das.h"
+#include "tegra_i2s.h"
+#include "tegra_pcm.h"
+#include "tegra_asoc_utils.h"
+
+#define DRV_NAME "tegra-snd-trimslice"
+
+struct tegra_trimslice {
+	struct tegra_asoc_utils_data util_data;
+};
+
+static int trimslice_asoc_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->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_card *card = codec->card;
+	struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card);
+	int srate, mclk;
+	int err;
+
+	srate = params_rate(params);
+	mclk = 128 * srate;
+
+	err = tegra_asoc_utils_set_rate(&trimslice->util_data, srate, mclk);
+	if (err < 0) {
+		dev_err(card->dev, "Can't configure clocks\n");
+		return err;
+	}
+
+	err = snd_soc_dai_set_fmt(codec_dai,
+					SND_SOC_DAIFMT_I2S |
+					SND_SOC_DAIFMT_NB_NF |
+					SND_SOC_DAIFMT_CBS_CFS);
+	if (err < 0) {
+		dev_err(card->dev, "codec_dai fmt not set\n");
+		return err;
+	}
+
+	err = snd_soc_dai_set_fmt(cpu_dai,
+					SND_SOC_DAIFMT_I2S |
+					SND_SOC_DAIFMT_NB_NF |
+					SND_SOC_DAIFMT_CBS_CFS);
+	if (err < 0) {
+		dev_err(card->dev, "cpu_dai fmt not set\n");
+		return err;
+	}
+
+	err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+					SND_SOC_CLOCK_IN);
+	if (err < 0) {
+		dev_err(card->dev, "codec_dai clock not set\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_ops trimslice_asoc_ops = {
+	.hw_params = trimslice_asoc_hw_params,
+};
+
+static const struct snd_soc_dapm_widget trimslice_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Line Out", NULL),
+	SND_SOC_DAPM_LINE("Line In", NULL),
+};
+
+static const struct snd_soc_dapm_route trimslice_audio_map[] = {
+	{"Line Out", NULL, "LOUT"},
+	{"Line Out", NULL, "ROUT"},
+
+	{"LLINEIN", NULL, "Line In"},
+	{"RLINEIN", NULL, "Line In"},
+};
+
+static int trimslice_asoc_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	snd_soc_dapm_nc_pin(dapm, "LHPOUT");
+	snd_soc_dapm_nc_pin(dapm, "RHPOUT");
+	snd_soc_dapm_nc_pin(dapm, "MICIN");
+
+	snd_soc_dapm_sync(dapm);
+
+	return 0;
+}
+
+static struct snd_soc_dai_link trimslice_tlv320aic23_dai = {
+	.name = "TLV320AIC23",
+	.stream_name = "AIC23",
+	.codec_name = "tlv320aic23-codec.2-001a",
+	.platform_name = "tegra-pcm-audio",
+	.cpu_dai_name = "tegra-i2s.0",
+	.codec_dai_name = "tlv320aic23-hifi",
+	.init = trimslice_asoc_init,
+	.ops = &trimslice_asoc_ops,
+};
+
+static struct snd_soc_card snd_soc_trimslice = {
+	.name = "tegra-trimslice",
+	.dai_link = &trimslice_tlv320aic23_dai,
+	.num_links = 1,
+
+	.dapm_widgets = trimslice_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(trimslice_dapm_widgets),
+	.dapm_routes = trimslice_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(trimslice_audio_map),
+};
+
+static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &snd_soc_trimslice;
+	struct tegra_trimslice *trimslice;
+	int ret;
+
+	trimslice = kzalloc(sizeof(struct tegra_trimslice), GFP_KERNEL);
+	if (!trimslice) {
+		dev_err(&pdev->dev, "Can't allocate tegra_trimslice\n");
+		return -ENOMEM;
+	}
+
+	ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev);
+	if (ret)
+		goto err_free_trimslice;
+
+	card->dev = &pdev->dev;
+	platform_set_drvdata(pdev, card);
+	snd_soc_card_set_drvdata(card, trimslice);
+
+	ret = snd_soc_register_card(card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+			ret);
+		goto err_fini_utils;
+	}
+
+	return 0;
+
+err_fini_utils:
+	tegra_asoc_utils_fini(&trimslice->util_data);
+err_free_trimslice:
+	kfree(trimslice);
+	return ret;
+}
+
+static int __devexit tegra_snd_trimslice_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card);
+
+	snd_soc_unregister_card(card);
+
+	tegra_asoc_utils_fini(&trimslice->util_data);
+
+	kfree(trimslice);
+
+	return 0;
+}
+
+static struct platform_driver tegra_snd_trimslice_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = tegra_snd_trimslice_probe,
+	.remove = __devexit_p(tegra_snd_trimslice_remove),
+};
+
+static int __init snd_tegra_trimslice_init(void)
+{
+	return platform_driver_register(&tegra_snd_trimslice_driver);
+}
+module_init(snd_tegra_trimslice_init);
+
+static void __exit snd_tegra_trimslice_exit(void)
+{
+	platform_driver_unregister(&tegra_snd_trimslice_driver);
+}
+module_exit(snd_tegra_trimslice_exit);
+
+MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
+MODULE_DESCRIPTION("Trimslice machine ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c
index 248463511186..ac828eff1a63 100644
--- a/sound/usb/6fire/control.c
+++ b/sound/usb/6fire/control.c
@@ -65,6 +65,15 @@ init_data[] = {
 	{ 0 } /* TERMINATING ENTRY */
 };
 
+static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 };
+/* values to write to soundcard register for all samplerates */
+static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
+static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
+
+enum {
+	DIGITAL_THRU_ONLY_SAMPLERATE = 3
+};
+
 static void usb6fire_control_master_vol_update(struct control_runtime *rt)
 {
 	struct comm_runtime *comm_rt = rt->chip->comm;
@@ -95,6 +104,67 @@ static void usb6fire_control_opt_coax_update(struct control_runtime *rt)
 	}
 }
 
+static int usb6fire_control_set_rate(struct control_runtime *rt, int rate)
+{
+	int ret;
+	struct usb_device *device = rt->chip->dev;
+	struct comm_runtime *comm_rt = rt->chip->comm;
+
+	if (rate < 0 || rate >= CONTROL_N_RATES)
+		return -EINVAL;
+
+	ret = usb_set_interface(device, 1, rates_altsetting[rate]);
+	if (ret < 0)
+		return ret;
+
+	/* set soundcard clock */
+	ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rate],
+			rates_6fire_vh[rate]);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int usb6fire_control_set_channels(
+	struct control_runtime *rt, int n_analog_out,
+	int n_analog_in, bool spdif_out, bool spdif_in)
+{
+	int ret;
+	struct comm_runtime *comm_rt = rt->chip->comm;
+
+	/* enable analog inputs and outputs
+	 * (one bit per stereo-channel) */
+	ret = comm_rt->write16(comm_rt, 0x02, 0x02,
+			(1 << (n_analog_out / 2)) - 1,
+			(1 << (n_analog_in / 2)) - 1);
+	if (ret < 0)
+		return ret;
+
+	/* disable digital inputs and outputs */
+	/* TODO: use spdif_x to enable/disable digital channels */
+	ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int usb6fire_control_streaming_update(struct control_runtime *rt)
+{
+	struct comm_runtime *comm_rt = rt->chip->comm;
+
+	if (comm_rt) {
+		if (!rt->usb_streaming && rt->digital_thru_switch)
+			usb6fire_control_set_rate(rt,
+				DIGITAL_THRU_ONLY_SAMPLERATE);
+		return comm_rt->write16(comm_rt, 0x02, 0x00, 0x00,
+			(rt->usb_streaming ? 0x01 : 0x00) |
+			(rt->digital_thru_switch ? 0x08 : 0x00));
+	}
+	return -EINVAL;
+}
+
 static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol,
 		struct snd_ctl_elem_info *uinfo)
 {
@@ -195,6 +265,28 @@ static int usb6fire_control_opt_coax_get(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
+static int usb6fire_control_digital_thru_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+	int changed = 0;
+
+	if (rt->digital_thru_switch != ucontrol->value.integer.value[0]) {
+		rt->digital_thru_switch = ucontrol->value.integer.value[0];
+		usb6fire_control_streaming_update(rt);
+		changed = 1;
+	}
+	return changed;
+}
+
+static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+	ucontrol->value.integer.value[0] = rt->digital_thru_switch;
+	return 0;
+}
+
 static struct __devinitdata snd_kcontrol_new elements[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -223,6 +315,15 @@ static struct __devinitdata snd_kcontrol_new elements[] = {
 		.get = usb6fire_control_opt_coax_get,
 		.put = usb6fire_control_opt_coax_put
 	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Digital Thru Playback Route",
+		.index = 0,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = snd_ctl_boolean_mono_info,
+		.get = usb6fire_control_digital_thru_get,
+		.put = usb6fire_control_digital_thru_put
+	},
 	{}
 };
 
@@ -238,6 +339,9 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip)
 		return -ENOMEM;
 
 	rt->chip = chip;
+	rt->update_streaming = usb6fire_control_streaming_update;
+	rt->set_rate = usb6fire_control_set_rate;
+	rt->set_channels = usb6fire_control_set_channels;
 
 	i = 0;
 	while (init_data[i].type) {
@@ -249,6 +353,7 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip)
 	usb6fire_control_opt_coax_update(rt);
 	usb6fire_control_line_phono_update(rt);
 	usb6fire_control_master_vol_update(rt);
+	usb6fire_control_streaming_update(rt);
 
 	i = 0;
 	while (elements[i].name) {
diff --git a/sound/usb/6fire/control.h b/sound/usb/6fire/control.h
index b534c777ab02..8f5aeead2e3d 100644
--- a/sound/usb/6fire/control.h
+++ b/sound/usb/6fire/control.h
@@ -21,12 +21,29 @@ enum {
 	CONTROL_MAX_ELEMENTS = 32
 };
 
+enum {
+	CONTROL_RATE_44KHZ,
+	CONTROL_RATE_48KHZ,
+	CONTROL_RATE_88KHZ,
+	CONTROL_RATE_96KHZ,
+	CONTROL_RATE_176KHZ,
+	CONTROL_RATE_192KHZ,
+	CONTROL_N_RATES
+};
+
 struct control_runtime {
+	int (*update_streaming)(struct control_runtime *rt);
+	int (*set_rate)(struct control_runtime *rt, int rate);
+	int (*set_channels)(struct control_runtime *rt, int n_analog_out,
+		int n_analog_in, bool spdif_out, bool spdif_in);
+
 	struct sfire_chip *chip;
 
 	struct snd_kcontrol *element[CONTROL_MAX_ELEMENTS];
 	bool opt_coax_switch;
 	bool line_phono_switch;
+	bool digital_thru_switch;
+	bool usb_streaming;
 	u8 master_vol;
 };
 
diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c
index 86c1a3103760..d47beffedb0f 100644
--- a/sound/usb/6fire/firmware.c
+++ b/sound/usb/6fire/firmware.c
@@ -3,12 +3,6 @@
  *
  * Firmware loader
  *
- * Currently not working for all devices. To be able to use the device
- * in linux, it is also possible to let the windows driver upload the firmware.
- * For that, start the computer in windows and reboot.
- * As long as the device is connected to the power supply, no firmware reload
- * needs to be performed.
- *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
  * Version:	0.3.0
@@ -21,6 +15,7 @@
  */
 
 #include <linux/firmware.h>
+#include <linux/bitrev.h>
 
 #include "firmware.h"
 #include "chip.h"
@@ -33,32 +28,6 @@ enum {
 	FPGA_BUFSIZE = 512, FPGA_EP = 2
 };
 
-static const u8 BIT_REVERSE_TABLE[256] = {
-	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50,
-	0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8,
-	0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04,
-	0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4,
-	0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c,
-	0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82,
-	0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32,
-	0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
-	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46,
-	0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6,
-	0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e,
-	0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1,
-	0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71,
-	0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99,
-	0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25,
-	0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
-	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d,
-	0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3,
-	0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b,
-	0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb,
-	0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67,
-	0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f,
-	0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f,
-	0xbf, 0x7f, 0xff };
-
 /*
  * wMaxPacketSize of pcm endpoints.
  * keep synced with rates_in_packet_size and rates_out_packet_size in pcm.c
@@ -72,6 +41,10 @@ static const u8 ep_w_max_packet_size[] = {
 	0x94, 0x01, 0x5c, 0x02  /* alt 3: 404 EP2 and 604 EP6 (25 fpp) */
 };
 
+static const u8 known_fw_versions[][4] = {
+	{ 0x03, 0x01, 0x0b, 0x00 }
+};
+
 struct ihex_record {
 	u16 address;
 	u8 len;
@@ -340,7 +313,7 @@ static int usb6fire_fw_fpga_upload(
 
 	while (c != end) {
 		for (i = 0; c != end && i < FPGA_BUFSIZE; i++, c++)
-			buffer[i] = BIT_REVERSE_TABLE[(u8) *c];
+			buffer[i] = byte_rev_table[(u8) *c];
 
 		ret = usb6fire_fw_fpga_write(device, buffer, i);
 		if (ret < 0) {
@@ -363,6 +336,25 @@ static int usb6fire_fw_fpga_upload(
 	return 0;
 }
 
+/* check, if the firmware version the devices has currently loaded
+ * is known by this driver. 'version' needs to have 4 bytes version
+ * info data. */
+static int usb6fire_fw_check(u8 *version)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(known_fw_versions); i++)
+		if (!memcmp(version, known_fw_versions + i, 4))
+			return 0;
+
+	snd_printk(KERN_ERR PREFIX "invalid fimware version in device: "
+			"%02x %02x %02x %02x. "
+			"please reconnect to power. if this failure "
+			"still happens, check your firmware installation.",
+			version[0], version[1], version[2], version[3]);
+	return -EINVAL;
+}
+
 int usb6fire_fw_init(struct usb_interface *intf)
 {
 	int i;
@@ -378,9 +370,7 @@ int usb6fire_fw_init(struct usb_interface *intf)
 				"firmware state.\n");
 		return ret;
 	}
-	if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55
-			|| buffer[4] != 0x03 || buffer[5] != 0x01 || buffer[7]
-			!= 0x00) {
+	if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55) {
 		snd_printk(KERN_ERR PREFIX "unknown device firmware state "
 				"received from device: ");
 		for (i = 0; i < 8; i++)
@@ -389,7 +379,7 @@ int usb6fire_fw_init(struct usb_interface *intf)
 		return -EIO;
 	}
 	/* do we need fpga loader ezusb firmware? */
-	if (buffer[3] == 0x01 && buffer[6] == 0x19) {
+	if (buffer[3] == 0x01) {
 		ret = usb6fire_fw_ezusb_upload(intf,
 				"6fire/dmx6firel2.ihx", 0, NULL, 0);
 		if (ret < 0)
@@ -397,7 +387,10 @@ int usb6fire_fw_init(struct usb_interface *intf)
 		return FW_NOT_READY;
 	}
 	/* do we need fpga firmware and application ezusb firmware? */
-	else if (buffer[3] == 0x02 && buffer[6] == 0x0b) {
+	else if (buffer[3] == 0x02) {
+		ret = usb6fire_fw_check(buffer + 4);
+		if (ret < 0)
+			return ret;
 		ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin");
 		if (ret < 0)
 			return ret;
@@ -410,8 +403,8 @@ int usb6fire_fw_init(struct usb_interface *intf)
 		return FW_NOT_READY;
 	}
 	/* all fw loaded? */
-	else if (buffer[3] == 0x03 && buffer[6] == 0x0b)
-		return 0;
+	else if (buffer[3] == 0x03)
+		return usb6fire_fw_check(buffer + 4);
 	/* unknown data? */
 	else {
 		snd_printk(KERN_ERR PREFIX "unknown device firmware state "
diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c
index ba62c7468ba8..b137b25865cc 100644
--- a/sound/usb/6fire/pcm.c
+++ b/sound/usb/6fire/pcm.c
@@ -17,26 +17,23 @@
 #include "pcm.h"
 #include "chip.h"
 #include "comm.h"
+#include "control.h"
 
 enum {
 	OUT_N_CHANNELS = 6, IN_N_CHANNELS = 4
 };
 
 /* keep next two synced with
- * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE */
+ * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE
+ * and CONTROL_RATE_XXX in control.h */
 static const int rates_in_packet_size[] = { 228, 228, 420, 420, 404, 404 };
 static const int rates_out_packet_size[] = { 228, 228, 420, 420, 604, 604 };
 static const int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000 };
-static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 };
 static const int rates_alsaid[] = {
 	SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_48000,
 	SNDRV_PCM_RATE_88200, SNDRV_PCM_RATE_96000,
 	SNDRV_PCM_RATE_176400, SNDRV_PCM_RATE_192000 };
 
-/* values to write to soundcard register for all samplerates */
-static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
-static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
-
 enum { /* settings for pcm */
 	OUT_EP = 6, IN_EP = 2, MAX_BUFSIZE = 128 * 1024
 };
@@ -48,15 +45,6 @@ enum { /* pcm streaming states */
 	STREAM_STOPPING
 };
 
-enum { /* pcm sample rates (also index into RATES_XXX[]) */
-	RATE_44KHZ,
-	RATE_48KHZ,
-	RATE_88KHZ,
-	RATE_96KHZ,
-	RATE_176KHZ,
-	RATE_192KHZ
-};
-
 static const struct snd_pcm_hardware pcm_hw = {
 	.info = SNDRV_PCM_INFO_MMAP |
 		SNDRV_PCM_INFO_INTERLEAVED |
@@ -64,7 +52,7 @@ static const struct snd_pcm_hardware pcm_hw = {
 		SNDRV_PCM_INFO_MMAP_VALID |
 		SNDRV_PCM_INFO_BATCH,
 
-	.formats = SNDRV_PCM_FMTBIT_S24_LE,
+	.formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
 
 	.rates = SNDRV_PCM_RATE_44100 |
 		SNDRV_PCM_RATE_48000 |
@@ -87,57 +75,34 @@ static const struct snd_pcm_hardware pcm_hw = {
 static int usb6fire_pcm_set_rate(struct pcm_runtime *rt)
 {
 	int ret;
-	struct usb_device *device = rt->chip->dev;
-	struct comm_runtime *comm_rt = rt->chip->comm;
+	struct control_runtime *ctrl_rt = rt->chip->control;
 
-	if (rt->rate >= ARRAY_SIZE(rates))
-		return -EINVAL;
-	/* disable streaming */
-	ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x00);
+	ctrl_rt->usb_streaming = false;
+	ret = ctrl_rt->update_streaming(ctrl_rt);
 	if (ret < 0) {
 		snd_printk(KERN_ERR PREFIX "error stopping streaming while "
 				"setting samplerate %d.\n", rates[rt->rate]);
 		return ret;
 	}
 
-	ret = usb_set_interface(device, 1, rates_altsetting[rt->rate]);
-	if (ret < 0) {
-		snd_printk(KERN_ERR PREFIX "error setting interface "
-				"altsetting %d for samplerate %d.\n",
-				rates_altsetting[rt->rate], rates[rt->rate]);
-		return ret;
-	}
-
-	/* set soundcard clock */
-	ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rt->rate],
-			rates_6fire_vh[rt->rate]);
+	ret = ctrl_rt->set_rate(ctrl_rt, rt->rate);
 	if (ret < 0) {
 		snd_printk(KERN_ERR PREFIX "error setting samplerate %d.\n",
 				rates[rt->rate]);
 		return ret;
 	}
 
-	/* enable analog inputs and outputs
-	 * (one bit per stereo-channel) */
-	ret = comm_rt->write16(comm_rt, 0x02, 0x02,
-			(1 << (OUT_N_CHANNELS / 2)) - 1,
-			(1 << (IN_N_CHANNELS / 2)) - 1);
+	ret = ctrl_rt->set_channels(ctrl_rt, OUT_N_CHANNELS, IN_N_CHANNELS,
+			false, false);
 	if (ret < 0) {
-		snd_printk(KERN_ERR PREFIX "error initializing analog channels "
+		snd_printk(KERN_ERR PREFIX "error initializing channels "
 				"while setting samplerate %d.\n",
 				rates[rt->rate]);
 		return ret;
 	}
-	/* disable digital inputs and outputs */
-	ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00);
-	if (ret < 0) {
-		snd_printk(KERN_ERR PREFIX "error initializing digital "
-				"channels while setting samplerate %d.\n",
-				rates[rt->rate]);
-		return ret;
-	}
 
-	ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x01);
+	ctrl_rt->usb_streaming = true;
+	ret = ctrl_rt->update_streaming(ctrl_rt);
 	if (ret < 0) {
 		snd_printk(KERN_ERR PREFIX "error starting streaming while "
 				"setting samplerate %d.\n", rates[rt->rate]);
@@ -168,12 +133,15 @@ static struct pcm_substream *usb6fire_pcm_get_substream(
 static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt)
 {
 	int i;
+	struct control_runtime *ctrl_rt = rt->chip->control;
 
 	if (rt->stream_state != STREAM_DISABLED) {
 		for (i = 0; i < PCM_N_URBS; i++) {
 			usb_kill_urb(&rt->in_urbs[i].instance);
 			usb_kill_urb(&rt->out_urbs[i].instance);
 		}
+		ctrl_rt->usb_streaming = false;
+		ctrl_rt->update_streaming(ctrl_rt);
 		rt->stream_state = STREAM_DISABLED;
 	}
 }
@@ -228,7 +196,7 @@ static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb)
 	unsigned int total_length = 0;
 	struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance);
 	struct snd_pcm_runtime *alsa_rt = sub->instance->runtime;
-	u32 *src = (u32 *) urb->buffer;
+	u32 *src = NULL;
 	u32 *dest = (u32 *) (alsa_rt->dma_area + sub->dma_off
 			* (alsa_rt->frame_bits >> 3));
 	u32 *dest_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size
@@ -244,7 +212,12 @@ static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb)
 		else
 			frame_count = 0;
 
-		src = (u32 *) (urb->buffer + total_length);
+		if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE)
+			src = (u32 *) (urb->buffer + total_length);
+		else if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE)
+			src = (u32 *) (urb->buffer - 1 + total_length);
+		else
+			return;
 		src++; /* skip leading 4 bytes of every packet */
 		total_length += urb->packets[i].length;
 		for (frame = 0; frame < frame_count; frame++) {
@@ -274,9 +247,18 @@ static void usb6fire_pcm_playback(struct pcm_substream *sub,
 			* (alsa_rt->frame_bits >> 3));
 	u32 *src_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size
 			* (alsa_rt->frame_bits >> 3));
-	u32 *dest = (u32 *) urb->buffer;
+	u32 *dest;
 	int bytes_per_frame = alsa_rt->channels << 2;
 
+	if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE)
+		dest = (u32 *) (urb->buffer - 1);
+	else if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE)
+		dest = (u32 *) (urb->buffer);
+	else {
+		snd_printk(KERN_ERR PREFIX "Unknown sample format.");
+		return;
+	}
+
 	for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) {
 		/* at least 4 header bytes for valid packet.
 		 * after that: 32 bits per sample for analog channels */
@@ -456,7 +438,7 @@ static int usb6fire_pcm_close(struct snd_pcm_substream *alsa_sub)
 		/* all substreams closed? if so, stop streaming */
 		if (!rt->playback.instance && !rt->capture.instance) {
 			usb6fire_pcm_stream_stop(rt);
-			rt->rate = -1;
+			rt->rate = ARRAY_SIZE(rates);
 		}
 	}
 	mutex_unlock(&rt->stream_mutex);
@@ -480,7 +462,6 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub)
 	struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
 	struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub);
 	struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime;
-	int i;
 	int ret;
 
 	if (rt->panic)
@@ -493,12 +474,10 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub)
 	sub->period_off = 0;
 
 	if (rt->stream_state == STREAM_DISABLED) {
-		for (i = 0; i < ARRAY_SIZE(rates); i++)
-			if (alsa_rt->rate == rates[i]) {
-				rt->rate = i;
+		for (rt->rate = 0; rt->rate < ARRAY_SIZE(rates); rt->rate++)
+			if (alsa_rt->rate == rates[rt->rate])
 				break;
-			}
-		if (i == ARRAY_SIZE(rates)) {
+		if (rt->rate == ARRAY_SIZE(rates)) {
 			mutex_unlock(&rt->stream_mutex);
 			snd_printk("invalid rate %d in prepare.\n",
 					alsa_rt->rate);
@@ -613,7 +592,7 @@ int __devinit usb6fire_pcm_init(struct sfire_chip *chip)
 
 	rt->chip = chip;
 	rt->stream_state = STREAM_DISABLED;
-	rt->rate = -1;
+	rt->rate = ARRAY_SIZE(rates);
 	init_waitqueue_head(&rt->stream_wait_queue);
 	mutex_init(&rt->stream_mutex);
 
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig
index 97724d8fa9f6..8beb77563da2 100644
--- a/sound/usb/Kconfig
+++ b/sound/usb/Kconfig
@@ -100,19 +100,17 @@ config SND_USB_US122L
 
 config SND_USB_6FIRE
         tristate "TerraTec DMX 6Fire USB"
-        depends on EXPERIMENTAL
         select FW_LOADER
+        select BITREVERSE
         select SND_RAWMIDI
         select SND_PCM
         help
           Say Y here to include support for TerraTec 6fire DMX USB interface.
 
           You will need firmware files in order to be able to use the device
-          after it has been coldstarted. This driver currently does not support
-          firmware loading for all devices. If you own such a device,
-          you could start windows and let the windows driver upload
-          the firmware. As long as you do not unplug your device from power,
-          it should be usable.
+          after it has been coldstarted. An install script for the firmware
+          and further help can be found at
+          http://sixfireusb.sourceforge.net
 
 endif	# SND_USB
 
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index 7754a1034545..075195e8661a 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -104,6 +104,15 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id)
 	int err;
 	unsigned char data;
 	struct usb_device *dev = chip->dev;
+	struct uac_clock_source_descriptor *cs_desc =
+		snd_usb_find_clock_source(chip->ctrl_intf, source_id);
+
+	if (!cs_desc)
+		return 0;
+
+	/* If a clock source can't tell us whether it's valid, we assume it is */
+	if (!uac2_control_is_readable(cs_desc->bmControls, UAC2_CS_CONTROL_CLOCK_VALID))
+		return 1;
 
 	err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
 			      USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
@@ -114,7 +123,7 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id)
 	if (err < 0) {
 		snd_printk(KERN_WARNING "%s(): cannot get clock validity for id %d\n",
 			   __func__, source_id);
-		return err;
+		return 0;
 	}
 
 	return !!data;
diff --git a/sound/usb/debug.h b/sound/usb/debug.h
index 343ec2d9ee66..58030176f008 100644
--- a/sound/usb/debug.h
+++ b/sound/usb/debug.h
@@ -8,7 +8,7 @@
 #ifdef HW_CONST_DEBUG
 #define hwc_debug(fmt, args...) printk(KERN_DEBUG fmt, ##args)
 #else
-#define hwc_debug(fmt, args...) /**/
+#define hwc_debug(fmt, args...) do { } while(0)
 #endif
 
 #endif /* __USBAUDIO_DEBUG_H */
diff --git a/sound/usb/format.c b/sound/usb/format.c
index f079b5e2ab28..8d042dce0d16 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -30,6 +30,7 @@
 #include "helper.h"
 #include "debug.h"
 #include "clock.h"
+#include "format.h"
 
 /*
  * parse the audio format type I descriptor
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 6ec33b62e6cf..eab06edcc9b7 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1097,11 +1097,13 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
 		append_ctl_name(kctl, control == UAC_FU_MUTE ?
 				" Switch" : " Volume");
 		if (control == UAC_FU_VOLUME) {
-			kctl->tlv.c = mixer_vol_tlv;
-			kctl->vd[0].access |= 
-				SNDRV_CTL_ELEM_ACCESS_TLV_READ |
-				SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
 			check_mapped_dB(map, cval);
+			if (cval->dBmin < cval->dBmax) {
+				kctl->tlv.c = mixer_vol_tlv;
+				kctl->vd[0].access |= 
+					SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+					SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+			}
 		}
 		break;
 
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 73dcc8256bc0..9146cffa6ede 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -61,6 +61,7 @@ static const struct rc_config {
 	{ USB_ID(0x041e, 0x3020), 2, 1, 6, 6,  18, 0x0013 }, /* Audigy 2 NX  */
 	{ USB_ID(0x041e, 0x3040), 2, 2, 6, 6,  2,  0x6e91 }, /* Live! 24-bit */
 	{ USB_ID(0x041e, 0x3042), 0, 1, 1, 1,  1,  0x000d }, /* Usb X-Fi S51 */
+	{ USB_ID(0x041e, 0x30df), 0, 1, 1, 1,  1,  0x000d }, /* Usb X-Fi S51 Pro */
 	{ USB_ID(0x041e, 0x3048), 2, 2, 6, 6,  2,  0x6e91 }, /* Toshiba SB0500 */
 };
 
@@ -188,6 +189,12 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
 			      usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
 			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
 			      !value, 0, NULL, 0, 100);
+	/* USB X-Fi S51 Pro */
+	if (mixer->chip->usb_id == USB_ID(0x041e, 0x30df))
+		err = snd_usb_ctl_msg(mixer->chip->dev,
+			      usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
+			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+			      !value, 0, NULL, 0, 100);
 	else
 		err = snd_usb_ctl_msg(mixer->chip->dev,
 			      usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
@@ -234,9 +241,13 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer)
 		/* USB X-Fi S51 doesn't have a CMSS LED */
 		if ((mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) && i == 0)
 			continue;
+		/* USB X-Fi S51 Pro doesn't have one either */
+		if ((mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) && i == 0)
+			continue;
 		if (i > 1 && /* Live24ext has 2 LEDs only */
 			(mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
 			 mixer->chip->usb_id == USB_ID(0x041e, 0x3042) ||
+			 mixer->chip->usb_id == USB_ID(0x041e, 0x30df) ||
 			 mixer->chip->usb_id == USB_ID(0x041e, 0x3048)))
 			break; 
 		err = snd_ctl_add(mixer->chip->card,
@@ -512,6 +523,7 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
 	case USB_ID(0x041e, 0x3020):
 	case USB_ID(0x041e, 0x3040):
 	case USB_ID(0x041e, 0x3042):
+	case USB_ID(0x041e, 0x30df):
 	case USB_ID(0x041e, 0x3048):
 		err = snd_audigy2nx_controls_create(mixer);
 		if (err < 0)
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index c66d3f64dcf8..78792a8900c3 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -1651,6 +1651,32 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 		}
 	}
 },
+{
+	USB_DEVICE(0x0582, 0x0127),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		/* .vendor_name = "Roland", */
+		/* .product_name = "GR-55", */
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = (const struct snd_usb_audio_quirk[]) {
+			{
+				.ifnum = 0,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 1,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 2,
+				.type = QUIRK_MIDI_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = -1
+			}
+		}
+	}
+},
 
 /* Guillemot devices */
 {
@@ -1953,7 +1979,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 	}
 },
 {
-	USB_DEVICE(0x0763, 0x2080),
+	USB_DEVICE_VENDOR_SPEC(0x0763, 0x2080),
 	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
 		/* .vendor_name = "M-Audio", */
 		/* .product_name = "Fast Track Ultra", */
@@ -2020,7 +2046,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 	}
 },
 {
-	USB_DEVICE(0x0763, 0x2081),
+	USB_DEVICE_VENDOR_SPEC(0x0763, 0x2081),
 	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
 		/* .vendor_name = "M-Audio", */
 		/* .product_name = "Fast Track Ultra 8R", */
@@ -2179,6 +2205,17 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 	}
 },
 
+/* KORG devices */
+{
+	USB_DEVICE_VENDOR_SPEC(0x0944, 0x0200),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.vendor_name = "KORG, Inc.",
+		/* .product_name = "PANDORA PX5D", */
+		.ifnum = 3,
+		.type = QUIRK_MIDI_STANDARD_INTERFACE,
+	}
+},
+
 /* AKAI devices */
 {
 	USB_DEVICE(0x09e8, 0x0062),
@@ -2332,6 +2369,12 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 
 /* Native Instruments MK2 series */
 {
+	/* Komplete Audio 6 */
+	.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor = 0x17cc,
+	.idProduct = 0x1000,
+},
+{
 	/* Traktor Audio 6 */
 	.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
 	.idVendor = 0x17cc,
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 1b94ec3a3368..bd13d7257240 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -540,6 +540,7 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,
 		/* Access Music VirusTI Desktop */
 		return snd_usb_accessmusic_boot_quirk(dev);
 
+	case USB_ID(0x17cc, 0x1000): /* Komplete Audio 6 */
 	case USB_ID(0x17cc, 0x1010): /* Traktor Audio 6 */
 	case USB_ID(0x17cc, 0x1020): /* Traktor Audio 10 */
 		return snd_usb_nativeinstruments_boot_quirk(dev);