summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Documentation/DocBook/writing-an-alsa-driver.tmpl12
-rw-r--r--Documentation/devicetree/bindings/sound/ak5386.txt19
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt26
-rw-r--r--Documentation/devicetree/bindings/sound/ti,tas5086.txt32
-rw-r--r--Documentation/sound/alsa/HD-Audio.txt10
-rw-r--r--arch/arm/mach-s3c24xx/dma-s3c2410.c2
-rw-r--r--arch/arm/mach-s3c24xx/dma-s3c2412.c2
-rw-r--r--arch/arm/mach-s3c24xx/dma-s3c2440.c2
-rw-r--r--arch/arm/mach-s3c24xx/dma-s3c2443.c2
-rw-r--r--arch/arm/plat-samsung/devs.c6
-rw-r--r--drivers/mfd/wm5102-tables.c10
-rw-r--r--include/linux/mfd/arizona/registers.h42
-rw-r--r--include/linux/mfd/wm8994/pdata.h8
-rw-r--r--include/linux/usb/audio-v2.h2
-rw-r--r--include/sound/compress_driver.h4
-rw-r--r--include/sound/control.h5
-rw-r--r--include/sound/core.h26
-rw-r--r--include/sound/dmaengine_pcm.h97
-rw-r--r--include/sound/emu10k1.h1
-rw-r--r--include/sound/pcm.h31
-rw-r--r--include/sound/soc-dai.h8
-rw-r--r--include/sound/soc-dapm.h1
-rw-r--r--include/sound/soc.h33
-rw-r--r--include/sound/tas5086.h7
-rw-r--r--include/sound/tegra_wm8903.h26
-rw-r--r--include/uapi/sound/asound.h4
-rw-r--r--sound/aoa/soundbus/i2sbus/pcm.c2
-rw-r--r--sound/atmel/ac97c.c4
-rw-r--r--sound/core/compress_offload.c128
-rw-r--r--sound/core/control.c41
-rw-r--r--sound/core/device.c8
-rw-r--r--sound/core/hwdep.c2
-rw-r--r--sound/core/info.c41
-rw-r--r--sound/core/init.c16
-rw-r--r--sound/core/isadma.c2
-rw-r--r--sound/core/jack.c6
-rw-r--r--sound/core/memalloc.c20
-rw-r--r--sound/core/memory.c4
-rw-r--r--sound/core/pcm.c8
-rw-r--r--sound/core/pcm_lib.c54
-rw-r--r--sound/core/pcm_memory.c19
-rw-r--r--sound/core/pcm_misc.c36
-rw-r--r--sound/core/pcm_native.c13
-rw-r--r--sound/core/rawmidi.c14
-rw-r--r--sound/core/sound.c7
-rw-r--r--sound/core/vmaster.c7
-rw-r--r--sound/drivers/Kconfig2
-rw-r--r--sound/drivers/aloop.c2
-rw-r--r--sound/drivers/mpu401/mpu401_uart.c6
-rw-r--r--sound/oss/dmabuf.c3
-rw-r--r--sound/oss/sb_common.c3
-rw-r--r--sound/oss/uart401.c11
-rw-r--r--sound/pci/ac97/ac97_codec.c16
-rw-r--r--sound/pci/ac97/ac97_pcm.c10
-rw-r--r--sound/pci/ali5451/ali5451.c8
-rw-r--r--sound/pci/asihpi/asihpi.c6
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c39
-rw-r--r--sound/pci/hda/hda_auto_parser.c68
-rw-r--r--sound/pci/hda/hda_auto_parser.h29
-rw-r--r--sound/pci/hda/hda_beep.c39
-rw-r--r--sound/pci/hda/hda_beep.h1
-rw-r--r--sound/pci/hda/hda_codec.c28
-rw-r--r--sound/pci/hda/hda_codec.h3
-rw-r--r--sound/pci/hda/hda_generic.c433
-rw-r--r--sound/pci/hda/hda_generic.h30
-rw-r--r--sound/pci/hda/hda_intel.c39
-rw-r--r--sound/pci/hda/hda_jack.c43
-rw-r--r--sound/pci/hda/hda_local.h4
-rw-r--r--sound/pci/hda/patch_analog.c33
-rw-r--r--sound/pci/hda/patch_ca0132.c82
-rw-r--r--sound/pci/hda/patch_cirrus.c19
-rw-r--r--sound/pci/hda/patch_conexant.c21
-rw-r--r--sound/pci/hda/patch_hdmi.c236
-rw-r--r--sound/pci/hda/patch_realtek.c715
-rw-r--r--sound/pci/hda/patch_sigmatel.c39
-rw-r--r--sound/pci/hda/patch_via.c20
-rw-r--r--sound/pci/rme9652/hdspm.c382
-rw-r--r--sound/soc/Kconfig4
-rw-r--r--sound/soc/Makefile4
-rw-r--r--sound/soc/atmel/atmel-pcm-dma.c29
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c54
-rw-r--r--sound/soc/au1x/ac97c.c9
-rw-r--r--sound/soc/au1x/i2sc.c9
-rw-r--r--sound/soc/au1x/psc-ac97.c9
-rw-r--r--sound/soc/au1x/psc-i2s.c9
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.c9
-rw-r--r--sound/soc/blackfin/bf5xx-i2s.c9
-rw-r--r--sound/soc/blackfin/bf5xx-tdm.c9
-rw-r--r--sound/soc/blackfin/bf6xx-i2s.c9
-rw-r--r--sound/soc/cirrus/edb93xx.c1
-rw-r--r--sound/soc/cirrus/ep93xx-ac97.c18
-rw-r--r--sound/soc/cirrus/ep93xx-i2s.c25
-rw-r--r--sound/soc/cirrus/ep93xx-pcm.c38
-rw-r--r--sound/soc/cirrus/ep93xx-pcm.h20
-rw-r--r--sound/soc/cirrus/simone.c2
-rw-r--r--sound/soc/cirrus/snappercl15.c1
-rw-r--r--sound/soc/codecs/Kconfig10
-rw-r--r--sound/soc/codecs/Makefile4
-rw-r--r--sound/soc/codecs/adau1373.c5
-rw-r--r--sound/soc/codecs/ak4104.c55
-rw-r--r--sound/soc/codecs/ak5386.c152
-rw-r--r--sound/soc/codecs/arizona.c497
-rw-r--r--sound/soc/codecs/arizona.h31
-rw-r--r--sound/soc/codecs/cs4271.c166
-rw-r--r--sound/soc/codecs/cs42l73.c6
-rw-r--r--sound/soc/codecs/max98088.c32
-rw-r--r--sound/soc/codecs/max98090.c45
-rw-r--r--sound/soc/codecs/si476x.c47
-rw-r--r--sound/soc/codecs/tas5086.c591
-rw-r--r--sound/soc/codecs/wm0010.c6
-rw-r--r--sound/soc/codecs/wm2000.c4
-rw-r--r--sound/soc/codecs/wm2000.h2
-rw-r--r--sound/soc/codecs/wm2200.c2
-rw-r--r--sound/soc/codecs/wm5102.c121
-rw-r--r--sound/soc/codecs/wm5102.h6
-rw-r--r--sound/soc/codecs/wm5110.c46
-rw-r--r--sound/soc/codecs/wm5110.h6
-rw-r--r--sound/soc/codecs/wm8903.c4
-rw-r--r--sound/soc/codecs/wm8960.c10
-rw-r--r--sound/soc/codecs/wm8994.c68
-rw-r--r--sound/soc/codecs/wm8994.h3
-rw-r--r--sound/soc/codecs/wm_adsp.c124
-rw-r--r--sound/soc/codecs/wm_adsp.h5
-rw-r--r--sound/soc/codecs/wm_hubs.c9
-rw-r--r--sound/soc/davinci/davinci-i2s.c15
-rw-r--r--sound/soc/davinci/davinci-mcasp.c110
-rw-r--r--sound/soc/davinci/davinci-mcasp.h2
-rw-r--r--sound/soc/davinci/davinci-pcm.c9
-rw-r--r--sound/soc/davinci/davinci-vcif.c11
-rw-r--r--sound/soc/dwc/designware_i2s.c9
-rw-r--r--sound/soc/fsl/Kconfig2
-rw-r--r--sound/soc/fsl/fsl_ssi.c64
-rw-r--r--sound/soc/fsl/fsl_ssi.h8
-rw-r--r--sound/soc/fsl/imx-audmux.c3
-rw-r--r--sound/soc/fsl/imx-pcm-dma.c120
-rw-r--r--sound/soc/fsl/imx-pcm-fiq.c6
-rw-r--r--sound/soc/fsl/imx-pcm.c6
-rw-r--r--sound/soc/fsl/imx-pcm.h24
-rw-r--r--sound/soc/fsl/imx-sgtl5000.c2
-rw-r--r--sound/soc/fsl/imx-ssi.c62
-rw-r--r--sound/soc/fsl/imx-ssi.h7
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.c8
-rw-r--r--sound/soc/fsl/mpc5200_psc_i2s.c9
-rw-r--r--sound/soc/jz4740/jz4740-i2s.c9
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.c11
-rw-r--r--sound/soc/mid-x86/sst_platform.c20
-rw-r--r--sound/soc/mid-x86/sst_platform.h2
-rw-r--r--sound/soc/mxs/Kconfig2
-rw-r--r--sound/soc/mxs/mxs-pcm.c176
-rw-r--r--sound/soc/mxs/mxs-pcm.h4
-rw-r--r--sound/soc/mxs/mxs-saif.c20
-rw-r--r--sound/soc/nuc900/nuc900-ac97.c9
-rw-r--r--sound/soc/omap/am3517evm.c1
-rw-r--r--sound/soc/omap/ams-delta.c1
-rw-r--r--sound/soc/omap/mcbsp.c14
-rw-r--r--sound/soc/omap/mcbsp.h7
-rw-r--r--sound/soc/omap/n810.c1
-rw-r--r--sound/soc/omap/omap-abe-twl6040.c1
-rw-r--r--sound/soc/omap/omap-dmic.c47
-rw-r--r--sound/soc/omap/omap-hdmi.c33
-rw-r--r--sound/soc/omap/omap-mcbsp.c27
-rw-r--r--sound/soc/omap/omap-mcpdm.c118
-rw-r--r--sound/soc/omap/omap-pcm.c86
-rw-r--r--sound/soc/omap/omap-pcm.h40
-rw-r--r--sound/soc/omap/omap-twl4030.c1
-rw-r--r--sound/soc/omap/omap3pandora.c9
-rw-r--r--sound/soc/omap/osk5912.c1
-rw-r--r--sound/soc/omap/rx51.c1
-rw-r--r--sound/soc/pxa/mmp-pcm.c34
-rw-r--r--sound/soc/pxa/mmp-sspa.c9
-rw-r--r--sound/soc/pxa/pxa-ssp.c9
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.c11
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.c9
-rw-r--r--sound/soc/s6000/s6000-i2s.c9
-rw-r--r--sound/soc/samsung/Kconfig5
-rw-r--r--sound/soc/samsung/ac97.c14
-rw-r--r--sound/soc/samsung/goni_wm8994.c11
-rw-r--r--sound/soc/samsung/h1940_uda1380.c2
-rw-r--r--sound/soc/samsung/i2s.c16
-rw-r--r--sound/soc/samsung/idma.c11
-rw-r--r--sound/soc/samsung/neo1973_wm8753.c3
-rw-r--r--sound/soc/samsung/pcm.c11
-rw-r--r--sound/soc/samsung/regs-ac97.h (renamed from arch/arm/plat-samsung/include/plat/regs-ac97.h)0
-rw-r--r--sound/soc/samsung/regs-iis.h (renamed from arch/arm/plat-samsung/include/plat/regs-iis.h)0
-rw-r--r--sound/soc/samsung/rx1950_uda1380.c2
-rw-r--r--sound/soc/samsung/s3c-i2s-v2.c9
-rw-r--r--sound/soc/samsung/s3c-i2s-v2.h7
-rw-r--r--sound/soc/samsung/s3c2412-i2s.c12
-rw-r--r--sound/soc/samsung/s3c24xx-i2s.c13
-rw-r--r--sound/soc/samsung/s3c24xx_uda134x.c2
-rw-r--r--sound/soc/samsung/spdif.c11
-rw-r--r--sound/soc/sh/fsi.c14
-rw-r--r--sound/soc/sh/hac.c10
-rw-r--r--sound/soc/sh/migor.c2
-rw-r--r--sound/soc/sh/siu_dai.c11
-rw-r--r--sound/soc/sh/ssi.c10
-rw-r--r--sound/soc/soc-compress.c38
-rw-r--r--sound/soc/soc-core.c213
-rw-r--r--sound/soc/soc-dapm.c320
-rw-r--r--sound/soc/soc-dmaengine-pcm.c150
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c300
-rw-r--r--sound/soc/soc-io.c5
-rw-r--r--sound/soc/soc-utils.c25
-rw-r--r--sound/soc/spear/spdif_in.c9
-rw-r--r--sound/soc/spear/spdif_out.c9
-rw-r--r--sound/soc/spear/spear_pcm.c23
-rw-r--r--sound/soc/tegra/Kconfig2
-rw-r--r--sound/soc/tegra/tegra20_ac97.c28
-rw-r--r--sound/soc/tegra/tegra20_ac97.h4
-rw-r--r--sound/soc/tegra/tegra20_i2s.c28
-rw-r--r--sound/soc/tegra/tegra20_i2s.h4
-rw-r--r--sound/soc/tegra/tegra20_spdif.c22
-rw-r--r--sound/soc/tegra/tegra20_spdif.h4
-rw-r--r--sound/soc/tegra/tegra30_ahub.c72
-rw-r--r--sound/soc/tegra/tegra30_ahub.h24
-rw-r--r--sound/soc/tegra/tegra30_i2s.c28
-rw-r--r--sound/soc/tegra/tegra30_i2s.h4
-rw-r--r--sound/soc/tegra/tegra_alc5632.c15
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.c34
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.h1
-rw-r--r--sound/soc/tegra/tegra_pcm.c187
-rw-r--r--sound/soc/tegra/tegra_pcm.h7
-rw-r--r--sound/soc/tegra/tegra_wm8753.c15
-rw-r--r--sound/soc/tegra/tegra_wm8903.c179
-rw-r--r--sound/soc/tegra/tegra_wm9712.c7
-rw-r--r--sound/soc/tegra/trimslice.c56
-rw-r--r--sound/soc/txx9/txx9aclc-ac97.c9
-rw-r--r--sound/soc/ux500/Kconfig2
-rw-r--r--sound/soc/ux500/ux500_msp_dai.c13
-rw-r--r--sound/soc/ux500/ux500_msp_dai.h5
-rw-r--r--sound/soc/ux500/ux500_msp_i2s.h1
-rw-r--r--sound/soc/ux500/ux500_pcm.c229
-rw-r--r--sound/soc/ux500/ux500_pcm.h14
-rw-r--r--sound/sound_core.c22
-rw-r--r--sound/spi/at73c213.c22
-rw-r--r--sound/usb/6fire/pcm.c1
-rw-r--r--sound/usb/caiaq/audio.c462
-rw-r--r--sound/usb/caiaq/audio.h4
-rw-r--r--sound/usb/caiaq/control.c67
-rw-r--r--sound/usb/caiaq/control.h2
-rw-r--r--sound/usb/caiaq/device.c248
-rw-r--r--sound/usb/caiaq/device.h18
-rw-r--r--sound/usb/caiaq/input.c336
-rw-r--r--sound/usb/caiaq/input.h6
-rw-r--r--sound/usb/caiaq/midi.c63
-rw-r--r--sound/usb/caiaq/midi.h5
-rw-r--r--sound/usb/card.c15
-rw-r--r--sound/usb/card.h9
-rw-r--r--sound/usb/clock.c189
-rw-r--r--sound/usb/clock.h3
-rw-r--r--sound/usb/endpoint.c32
-rw-r--r--sound/usb/endpoint.h2
-rw-r--r--sound/usb/format.c30
-rw-r--r--sound/usb/format.h2
-rw-r--r--sound/usb/helper.c10
-rw-r--r--sound/usb/midi.c25
-rw-r--r--sound/usb/misc/ua101.c3
-rw-r--r--sound/usb/pcm.c158
-rw-r--r--sound/usb/proc.c9
-rw-r--r--sound/usb/quirks-table.h121
-rw-r--r--sound/usb/quirks.c60
-rw-r--r--sound/usb/quirks.h5
-rw-r--r--sound/usb/stream.c23
-rw-r--r--sound/usb/usbaudio.h1
-rw-r--r--sound/usb/usx2y/usb_stream.c1
-rw-r--r--sound/usb/usx2y/usbusx2yaudio.c1
-rw-r--r--sound/usb/usx2y/usx2yhwdeppcm.c1
267 files changed, 7241 insertions, 3721 deletions
diff --git a/Documentation/DocBook/writing-an-alsa-driver.tmpl b/Documentation/DocBook/writing-an-alsa-driver.tmpl
index bd6fee22c4dd..06741e925985 100644
--- a/Documentation/DocBook/writing-an-alsa-driver.tmpl
+++ b/Documentation/DocBook/writing-an-alsa-driver.tmpl
@@ -6164,14 +6164,12 @@ struct _snd_pcm_runtime {
 
       <para>
         The macro takes an conditional expression to evaluate.
-	When <constant>CONFIG_SND_DEBUG</constant>, is set, the
-	expression is actually evaluated. If it's non-zero, it shows
-	the warning message such as
+	When <constant>CONFIG_SND_DEBUG</constant>, is set, if the
+	expression is non-zero, it shows the warning message such as
 	<computeroutput>BUG? (xxx)</computeroutput>
-	normally followed by stack trace.  It returns the evaluated
-	value.
-	When no <constant>CONFIG_SND_DEBUG</constant> is set, this
-	macro always returns zero.
+	normally followed by stack trace.
+
+	In both cases it returns the evaluated value.
       </para>
 
     </section>
diff --git a/Documentation/devicetree/bindings/sound/ak5386.txt b/Documentation/devicetree/bindings/sound/ak5386.txt
new file mode 100644
index 000000000000..dc3914fe6ce8
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ak5386.txt
@@ -0,0 +1,19 @@
+AK5386 Single-ended 24-Bit 192kHz delta-sigma ADC
+
+This device has no control interface.
+
+Required properties:
+
+  - compatible : "asahi-kasei,ak5386"
+
+Optional properties:
+
+  - reset-gpio : a GPIO spec for the reset/power down pin.
+		 If specified, it will be deasserted at probe time.
+
+Example:
+
+spdif: ak5386@0 {
+	compatible = "asahi-kasei,ak5386";
+	reset-gpio = <&gpio0 23>;
+};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt
index 1ac7b1642186..0e5c12c66523 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt
@@ -1,12 +1,22 @@
 NVIDIA Tegra30 AHUB (Audio Hub)
 
 Required properties:
-- compatible : "nvidia,tegra30-ahub"
+- compatible : "nvidia,tegra30-ahub", "nvidia,tegra114-ahub", etc.
 - reg : Should contain the register physical address and length for each of
-  the AHUB's APBIF registers and the AHUB's own registers.
+  the AHUB's register blocks.
+  - Tegra30 requires 2 entries, for the APBIF and AHUB/AUDIO register blocks.
+  - Tegra114 requires an additional entry, for the APBIF2 register block.
 - interrupts : Should contain AHUB interrupt
-- nvidia,dma-request-selector : The Tegra DMA controller's phandle and
-  request selector for the first APBIF channel.
+- nvidia,dma-request-selector : A list of the DMA channel specifiers. Each
+  entry contains the Tegra DMA controller's phandle and request selector.
+  If a single entry is present, the request selectors for the channels are
+  assumed to be contiguous, and increment from this value.
+  If multiple values are given, one value must be given per channel.
+- clocks : Must contain an entry for each required entry in clock-names.
+- clock-names : Must include the following entries:
+  - Tegra30: Requires d_audio, apbif, i2s0, i2s1, i2s2, i2s3, i2s4, dam0,
+    dam1, dam2, spdif_in.
+  - Tegra114: Additionally requires amx, adx.
 - ranges : The bus address mapping for the configlink register bus.
   Can be empty since the mapping is 1:1.
 - #address-cells : For the configlink bus. Should be <1>;
@@ -25,7 +35,13 @@ ahub@70080000 {
 	reg = <0x70080000 0x200 0x70080200 0x100>;
 	interrupts = < 0 103 0x04 >;
 	nvidia,dma-request-selector = <&apbdma 1>;
-
+	clocks = <&tegra_car 106>, <&tegra_car 107>, <&tegra_car 30>,
+		<&tegra_car 11>, <&tegra_car 18>, <&tegra_car 101>,
+		<&tegra_car 102>, <&tegra_car 108>, <&tegra_car 109>,
+		<&tegra_car 110>, <&tegra_car 162>;
+	clock-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2",
+		"i2s3", "i2s4", "dam0", "dam1", "dam2",
+		"spdif_in";
 	ranges;
 	#address-cells = <1>;
 	#size-cells = <1>;
diff --git a/Documentation/devicetree/bindings/sound/ti,tas5086.txt b/Documentation/devicetree/bindings/sound/ti,tas5086.txt
new file mode 100644
index 000000000000..8ea4f5b4818d
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ti,tas5086.txt
@@ -0,0 +1,32 @@
+Texas Instruments TAS5086 6-channel PWM Processor
+
+Required properties:
+
+ - compatible:		Should contain "ti,tas5086".
+ - reg:			The i2c address. Should contain <0x1b>.
+
+Optional properties:
+
+ - reset-gpio: 		A GPIO spec to define which pin is connected to the
+			chip's !RESET pin. If specified, the driver will
+			assert a hardware reset at probe time.
+
+ - ti,charge-period:	This property should contain the time in microseconds
+			that closely matches the external single-ended
+			split-capacitor charge period. The hardware chip
+			waits for this period of time before starting the
+			PWM signals. This helps reduce pops and clicks.
+
+			When not specified, the hardware default of 1300ms
+			is retained.
+
+Examples:
+
+	i2c_bus {
+		tas5086@1b {
+			compatible = "ti,tas5086";
+			reg = <0x1b>;
+			reset-gpio = <&gpio 23 0>;
+			ti,charge-period = <156000>;
+		};
+	};
diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt
index d4faa63ff352..c3c912d023cc 100644
--- a/Documentation/sound/alsa/HD-Audio.txt
+++ b/Documentation/sound/alsa/HD-Audio.txt
@@ -461,11 +461,13 @@ The generic parser supports the following hints:
   the corresponding mixer control, if available
 - add_stereo_mix_input (bool): add the stereo mix (analog-loopback
   mix) to the input mux if available
-- add_out_jack_modes (bool): add "xxx Jack Mode" enum controls to each
-  output jack for allowing to change the headphone amp capability
-- add_in_jack_modes (bool): add "xxx Jack Mode" enum controls to each
-  input jack for allowing to change the mic bias vref
+- add_jack_modes (bool): add "xxx Jack Mode" enum controls to each
+  I/O jack for allowing to change the headphone amp and mic bias VREF
+  capabilities
 - power_down_unused (bool): power down the unused widgets
+- add_hp_mic (bool): add the headphone to capture source if possible
+- hp_mic_detect (bool): enable/disable the hp/mic shared input for a
+  single built-in mic case; default true
 - mixer_nid (int): specifies the widget NID of the analog-loopback
   mixer
 
diff --git a/arch/arm/mach-s3c24xx/dma-s3c2410.c b/arch/arm/mach-s3c24xx/dma-s3c2410.c
index a6c94b820954..30aa53ff07a6 100644
--- a/arch/arm/mach-s3c24xx/dma-s3c2410.c
+++ b/arch/arm/mach-s3c24xx/dma-s3c2410.c
@@ -25,10 +25,8 @@
 
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
-#include <plat/regs-ac97.h>
 #include <plat/regs-dma.h>
 #include <mach/regs-lcd.h>
-#include <plat/regs-iis.h>
 #include <plat/regs-spi.h>
 
 static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = {
diff --git a/arch/arm/mach-s3c24xx/dma-s3c2412.c b/arch/arm/mach-s3c24xx/dma-s3c2412.c
index c0e8c3f5057e..ab1700ec8e64 100644
--- a/arch/arm/mach-s3c24xx/dma-s3c2412.c
+++ b/arch/arm/mach-s3c24xx/dma-s3c2412.c
@@ -25,10 +25,8 @@
 
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
-#include <plat/regs-ac97.h>
 #include <plat/regs-dma.h>
 #include <mach/regs-lcd.h>
-#include <plat/regs-iis.h>
 #include <plat/regs-spi.h>
 
 #define MAP(x) { (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID }
diff --git a/arch/arm/mach-s3c24xx/dma-s3c2440.c b/arch/arm/mach-s3c24xx/dma-s3c2440.c
index 1c08eccd9425..cd25de28804c 100644
--- a/arch/arm/mach-s3c24xx/dma-s3c2440.c
+++ b/arch/arm/mach-s3c24xx/dma-s3c2440.c
@@ -25,10 +25,8 @@
 
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
-#include <plat/regs-ac97.h>
 #include <plat/regs-dma.h>
 #include <mach/regs-lcd.h>
-#include <plat/regs-iis.h>
 #include <plat/regs-spi.h>
 
 static struct s3c24xx_dma_map __initdata s3c2440_dma_mappings[] = {
diff --git a/arch/arm/mach-s3c24xx/dma-s3c2443.c b/arch/arm/mach-s3c24xx/dma-s3c2443.c
index 000e4c69fce9..5fe3539dc2b5 100644
--- a/arch/arm/mach-s3c24xx/dma-s3c2443.c
+++ b/arch/arm/mach-s3c24xx/dma-s3c2443.c
@@ -25,10 +25,8 @@
 
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
-#include <plat/regs-ac97.h>
 #include <plat/regs-dma.h>
 #include <mach/regs-lcd.h>
-#include <plat/regs-iis.h>
 #include <plat/regs-spi.h>
 
 #define MAP(x) { \
diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index 8f456bed4fa0..33ad3f32c2b9 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -146,14 +146,20 @@ struct platform_device s3c_device_camif = {
 
 /* ASOC DMA */
 
+#ifdef CONFIG_PLAT_S5P 
+static struct resource samsung_asoc_idma_resource = DEFINE_RES_IRQ(IRQ_I2S0);
+
 struct platform_device samsung_asoc_idma = {
 	.name		= "samsung-idma",
 	.id		= -1,
+	.num_resources	= 1,
+	.resource	= &samsung_asoc_idma_resource,
 	.dev		= {
 		.dma_mask		= &samsung_device_dma_mask,
 		.coherent_dma_mask	= DMA_BIT_MASK(32),
 	}
 };
+#endif
 
 /* FB */
 
diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c
index ca2aed6bc830..f70c4956ff9d 100644
--- a/drivers/mfd/wm5102-tables.c
+++ b/drivers/mfd/wm5102-tables.c
@@ -290,12 +290,14 @@ static const struct reg_default wm5102_reg_default[] = {
 	{ 0x00000176, 0x0000 },   /* R374   - FLL1 Control 6 */ 
 	{ 0x00000177, 0x0181 },   /* R375   - FLL1 Loop Filter Test 1 */ 
 	{ 0x00000178, 0x0000 },   /* R376   - FLL1 NCO Test 0 */
+	{ 0x00000179, 0x0000 },   /* R377   - FLL1 Control 7 */
 	{ 0x00000181, 0x0000 },   /* R385   - FLL1 Synchroniser 1 */ 
 	{ 0x00000182, 0x0000 },   /* R386   - FLL1 Synchroniser 2 */ 
 	{ 0x00000183, 0x0000 },   /* R387   - FLL1 Synchroniser 3 */ 
 	{ 0x00000184, 0x0000 },   /* R388   - FLL1 Synchroniser 4 */ 
 	{ 0x00000185, 0x0000 },   /* R389   - FLL1 Synchroniser 5 */ 
 	{ 0x00000186, 0x0000 },   /* R390   - FLL1 Synchroniser 6 */ 
+	{ 0x00000187, 0x0001 },   /* R391   - FLL1 Synchroniser 7 */
 	{ 0x00000189, 0x0000 },   /* R393   - FLL1 Spread Spectrum */ 
 	{ 0x0000018A, 0x0004 },   /* R394   - FLL1 GPIO Clock */ 
 	{ 0x00000191, 0x0000 },   /* R401   - FLL2 Control 1 */ 
@@ -306,12 +308,14 @@ static const struct reg_default wm5102_reg_default[] = {
 	{ 0x00000196, 0x0000 },   /* R406   - FLL2 Control 6 */ 
 	{ 0x00000197, 0x0000 },   /* R407   - FLL2 Loop Filter Test 1 */ 
 	{ 0x00000198, 0x0000 },   /* R408   - FLL2 NCO Test 0 */
+	{ 0x00000199, 0x0000 },   /* R409   - FLL2 Control 7 */
 	{ 0x000001A1, 0x0000 },   /* R417   - FLL2 Synchroniser 1 */ 
 	{ 0x000001A2, 0x0000 },   /* R418   - FLL2 Synchroniser 2 */ 
 	{ 0x000001A3, 0x0000 },   /* R419   - FLL2 Synchroniser 3 */ 
 	{ 0x000001A4, 0x0000 },   /* R420   - FLL2 Synchroniser 4 */ 
 	{ 0x000001A5, 0x0000 },   /* R421   - FLL2 Synchroniser 5 */ 
 	{ 0x000001A6, 0x0000 },   /* R422   - FLL2 Synchroniser 6 */ 
+	{ 0x000001A7, 0x0001 },   /* R423   - FLL2 Synchroniser 7 */
 	{ 0x000001A9, 0x0000 },   /* R425   - FLL2 Spread Spectrum */ 
 	{ 0x000001AA, 0x0004 },   /* R426   - FLL2 GPIO Clock */ 
 	{ 0x00000200, 0x0006 },   /* R512   - Mic Charge Pump 1 */ 
@@ -1055,12 +1059,14 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
 	case ARIZONA_FLL1_CONTROL_6:
 	case ARIZONA_FLL1_LOOP_FILTER_TEST_1:
 	case ARIZONA_FLL1_NCO_TEST_0:
+	case ARIZONA_FLL1_CONTROL_7:
 	case ARIZONA_FLL1_SYNCHRONISER_1:
 	case ARIZONA_FLL1_SYNCHRONISER_2:
 	case ARIZONA_FLL1_SYNCHRONISER_3:
 	case ARIZONA_FLL1_SYNCHRONISER_4:
 	case ARIZONA_FLL1_SYNCHRONISER_5:
 	case ARIZONA_FLL1_SYNCHRONISER_6:
+	case ARIZONA_FLL1_SYNCHRONISER_7:
 	case ARIZONA_FLL1_SPREAD_SPECTRUM:
 	case ARIZONA_FLL1_GPIO_CLOCK:
 	case ARIZONA_FLL2_CONTROL_1:
@@ -1071,12 +1077,14 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
 	case ARIZONA_FLL2_CONTROL_6:
 	case ARIZONA_FLL2_LOOP_FILTER_TEST_1:
 	case ARIZONA_FLL2_NCO_TEST_0:
+	case ARIZONA_FLL2_CONTROL_7:
 	case ARIZONA_FLL2_SYNCHRONISER_1:
 	case ARIZONA_FLL2_SYNCHRONISER_2:
 	case ARIZONA_FLL2_SYNCHRONISER_3:
 	case ARIZONA_FLL2_SYNCHRONISER_4:
 	case ARIZONA_FLL2_SYNCHRONISER_5:
 	case ARIZONA_FLL2_SYNCHRONISER_6:
+	case ARIZONA_FLL2_SYNCHRONISER_7:
 	case ARIZONA_FLL2_SPREAD_SPECTRUM:
 	case ARIZONA_FLL2_GPIO_CLOCK:
 	case ARIZONA_MIC_CHARGE_PUMP_1:
@@ -1169,6 +1177,8 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
 	case ARIZONA_NOISE_GATE_CONTROL:
 	case ARIZONA_PDM_SPK1_CTRL_1:
 	case ARIZONA_PDM_SPK1_CTRL_2:
+	case ARIZONA_SPK_CTRL_2:
+	case ARIZONA_SPK_CTRL_3:
 	case ARIZONA_DAC_COMP_1:
 	case ARIZONA_DAC_COMP_2:
 	case ARIZONA_DAC_COMP_3:
diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h
index f43aa7c8d040..715b6ba3d52a 100644
--- a/include/linux/mfd/arizona/registers.h
+++ b/include/linux/mfd/arizona/registers.h
@@ -85,12 +85,14 @@
 #define ARIZONA_FLL1_CONTROL_6                   0x176
 #define ARIZONA_FLL1_LOOP_FILTER_TEST_1          0x177
 #define ARIZONA_FLL1_NCO_TEST_0                  0x178
+#define ARIZONA_FLL1_CONTROL_7                   0x179
 #define ARIZONA_FLL1_SYNCHRONISER_1              0x181
 #define ARIZONA_FLL1_SYNCHRONISER_2              0x182
 #define ARIZONA_FLL1_SYNCHRONISER_3              0x183
 #define ARIZONA_FLL1_SYNCHRONISER_4              0x184
 #define ARIZONA_FLL1_SYNCHRONISER_5              0x185
 #define ARIZONA_FLL1_SYNCHRONISER_6              0x186
+#define ARIZONA_FLL1_SYNCHRONISER_7              0x187
 #define ARIZONA_FLL1_SPREAD_SPECTRUM             0x189
 #define ARIZONA_FLL1_GPIO_CLOCK                  0x18A
 #define ARIZONA_FLL2_CONTROL_1                   0x191
@@ -101,12 +103,14 @@
 #define ARIZONA_FLL2_CONTROL_6                   0x196
 #define ARIZONA_FLL2_LOOP_FILTER_TEST_1          0x197
 #define ARIZONA_FLL2_NCO_TEST_0                  0x198
+#define ARIZONA_FLL2_CONTROL_7                   0x199
 #define ARIZONA_FLL2_SYNCHRONISER_1              0x1A1
 #define ARIZONA_FLL2_SYNCHRONISER_2              0x1A2
 #define ARIZONA_FLL2_SYNCHRONISER_3              0x1A3
 #define ARIZONA_FLL2_SYNCHRONISER_4              0x1A4
 #define ARIZONA_FLL2_SYNCHRONISER_5              0x1A5
 #define ARIZONA_FLL2_SYNCHRONISER_6              0x1A6
+#define ARIZONA_FLL2_SYNCHRONISER_7              0x1A7
 #define ARIZONA_FLL2_SPREAD_SPECTRUM             0x1A9
 #define ARIZONA_FLL2_GPIO_CLOCK                  0x1AA
 #define ARIZONA_MIC_CHARGE_PUMP_1                0x200
@@ -217,6 +221,8 @@
 #define ARIZONA_PDM_SPK1_CTRL_2                  0x491
 #define ARIZONA_PDM_SPK2_CTRL_1                  0x492
 #define ARIZONA_PDM_SPK2_CTRL_2                  0x493
+#define ARIZONA_SPK_CTRL_2                       0x4B5
+#define ARIZONA_SPK_CTRL_3                       0x4B6
 #define ARIZONA_DAC_COMP_1                       0x4DC
 #define ARIZONA_DAC_COMP_2                       0x4DD
 #define ARIZONA_DAC_COMP_3                       0x4DE
@@ -1682,6 +1688,13 @@
 #define ARIZONA_FLL1_FRC_INTEG_VAL_WIDTH             12  /* FLL1_FRC_INTEG_VAL - [11:0] */
 
 /*
+ * R377 (0x179) - FLL1 Control 7
+ */
+#define ARIZONA_FLL1_GAIN_MASK                   0x003c  /* FLL1_GAIN */
+#define ARIZONA_FLL1_GAIN_SHIFT                       2  /* FLL1_GAIN */
+#define ARIZONA_FLL1_GAIN_WIDTH                       4  /* FLL1_GAIN */
+
+/*
  * R385 (0x181) - FLL1 Synchroniser 1
  */
 #define ARIZONA_FLL1_SYNC_ENA                    0x0001  /* FLL1_SYNC_ENA */
@@ -1728,6 +1741,17 @@
 #define ARIZONA_FLL1_CLK_SYNC_SRC_WIDTH               4  /* FLL1_CLK_SYNC_SRC - [3:0] */
 
 /*
+ * R391 (0x187) - FLL1 Synchroniser 7
+ */
+#define ARIZONA_FLL1_SYNC_GAIN_MASK              0x003c  /* FLL1_SYNC_GAIN */
+#define ARIZONA_FLL1_SYNC_GAIN_SHIFT                  2  /* FLL1_SYNC_GAIN */
+#define ARIZONA_FLL1_SYNC_GAIN_WIDTH                  4  /* FLL1_SYNC_GAIN */
+#define ARIZONA_FLL1_SYNC_BW                     0x0001  /* FLL1_SYNC_BW */
+#define ARIZONA_FLL1_SYNC_BW_MASK                0x0001  /* FLL1_SYNC_BW */
+#define ARIZONA_FLL1_SYNC_BW_SHIFT                    0  /* FLL1_SYNC_BW */
+#define ARIZONA_FLL1_SYNC_BW_WIDTH                    1  /* FLL1_SYNC_BW */
+
+/*
  * R393 (0x189) - FLL1 Spread Spectrum
  */
 #define ARIZONA_FLL1_SS_AMPL_MASK                0x0030  /* FLL1_SS_AMPL - [5:4] */
@@ -1820,6 +1844,13 @@
 #define ARIZONA_FLL2_FRC_INTEG_VAL_WIDTH             12  /* FLL2_FRC_INTEG_VAL - [11:0] */
 
 /*
+ * R409 (0x199) - FLL2 Control 7
+ */
+#define ARIZONA_FLL2_GAIN_MASK                   0x003c  /* FLL2_GAIN */
+#define ARIZONA_FLL2_GAIN_SHIFT                       2  /* FLL2_GAIN */
+#define ARIZONA_FLL2_GAIN_WIDTH                       4  /* FLL2_GAIN */
+
+/*
  * R417 (0x1A1) - FLL2 Synchroniser 1
  */
 #define ARIZONA_FLL2_SYNC_ENA                    0x0001  /* FLL2_SYNC_ENA */
@@ -1866,6 +1897,17 @@
 #define ARIZONA_FLL2_CLK_SYNC_SRC_WIDTH               4  /* FLL2_CLK_SYNC_SRC - [3:0] */
 
 /*
+ * R423 (0x1A7) - FLL2 Synchroniser 7
+ */
+#define ARIZONA_FLL2_SYNC_GAIN_MASK              0x003c  /* FLL2_SYNC_GAIN */
+#define ARIZONA_FLL2_SYNC_GAIN_SHIFT                  2  /* FLL2_SYNC_GAIN */
+#define ARIZONA_FLL2_SYNC_GAIN_WIDTH                  4  /* FLL2_SYNC_GAIN */
+#define ARIZONA_FLL2_SYNC_BW_MASK                0x0001  /* FLL2_SYNC_BW */
+#define ARIZONA_FLL2_SYNC_BW_MASK                0x0001  /* FLL2_SYNC_BW */
+#define ARIZONA_FLL2_SYNC_BW_SHIFT                    0  /* FLL2_SYNC_BW */
+#define ARIZONA_FLL2_SYNC_BW_WIDTH                    1  /* FLL2_SYNC_BW */
+
+/*
  * R425 (0x1A9) - FLL2 Spread Spectrum
  */
 #define ARIZONA_FLL2_SS_AMPL_MASK                0x0030  /* FLL2_SS_AMPL - [5:4] */
diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h
index 8e21a094836d..68e776594889 100644
--- a/include/linux/mfd/wm8994/pdata.h
+++ b/include/linux/mfd/wm8994/pdata.h
@@ -17,6 +17,7 @@
 
 #define WM8994_NUM_LDO   2
 #define WM8994_NUM_GPIO 11
+#define WM8994_NUM_AIF   3
 
 struct wm8994_ldo_pdata {
 	/** GPIOs to enable regulator, 0 or less if not available */
@@ -215,6 +216,13 @@ struct wm8994_pdata {
 	 * system.
 	 */
 	bool spkmode_pu;
+
+	/**
+	 * Maximum number of channels clocks will be generated for,
+	 * useful for systems where and I2S bus with multiple data
+	 * lines is mastered.
+	 */
+	int max_channels_clocked[WM8994_NUM_AIF];
 };
 
 #endif
diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h
index ed13053153f4..c5f2158ab00e 100644
--- a/include/linux/usb/audio-v2.h
+++ b/include/linux/usb/audio-v2.h
@@ -170,6 +170,8 @@ struct uac2_as_header_descriptor {
 	__u8 iChannelNames;
 } __attribute__((packed));
 
+#define UAC2_FORMAT_TYPE_I_RAW_DATA	(1 << 31)
+
 /* 4.10.1.2 Class-Specific AS Isochronous Audio Data Endpoint Descriptor */
 
 struct uac2_iso_endpoint_descriptor {
diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h
index ff6c74153fa1..9031a26249b5 100644
--- a/include/sound/compress_driver.h
+++ b/include/sound/compress_driver.h
@@ -56,8 +56,6 @@ struct snd_compr_runtime {
 	u64 buffer_size;
 	u32 fragment_size;
 	u32 fragments;
-	u64 hw_pointer;
-	u64 app_pointer;
 	u64 total_bytes_available;
 	u64 total_bytes_transferred;
 	wait_queue_head_t sleep;
@@ -121,7 +119,7 @@ struct snd_compr_ops {
 	int (*trigger)(struct snd_compr_stream *stream, int cmd);
 	int (*pointer)(struct snd_compr_stream *stream,
 			struct snd_compr_tstamp *tstamp);
-	int (*copy)(struct snd_compr_stream *stream, const char __user *buf,
+	int (*copy)(struct snd_compr_stream *stream, char __user *buf,
 		       size_t count);
 	int (*mmap)(struct snd_compr_stream *stream,
 			struct vm_area_struct *vma);
diff --git a/include/sound/control.h b/include/sound/control.h
index 8332e865c759..34bc93d80d55 100644
--- a/include/sound/control.h
+++ b/include/sound/control.h
@@ -189,7 +189,6 @@ int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave,
  *
  * Add a virtual slave control to the given master element created via
  * snd_ctl_create_virtual_master() beforehand.
- * Returns zero if successful or a negative error code.
  *
  * All slaves must be the same type (returning the same information
  * via info callback).  The function doesn't check it, so it's your
@@ -199,6 +198,8 @@ int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave,
  * at most two channels,
  * logarithmic volume control (dB level) thus no linear volume,
  * master can only attenuate the volume without gain
+ *
+ * Return: Zero if successful or a negative error code.
  */
 static inline int
 snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
@@ -219,6 +220,8 @@ snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
  * When the control peeks the hardware values directly and the value
  * can be changed by other means than the put callback of the element,
  * this function should be used to keep the value always up-to-date.
+ *
+ * Return: Zero if successful or a negative error code.
  */
 static inline int
 snd_ctl_add_slave_uncached(struct snd_kcontrol *master,
diff --git a/include/sound/core.h b/include/sound/core.h
index 7cede2d6aa86..5bfe5136441c 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -229,7 +229,7 @@ int snd_register_device_for_dev(int type, struct snd_card *card,
  * This function uses the card's device pointer to link to the
  * correct &struct device.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 static inline int snd_register_device(int type, struct snd_card *card, int dev,
 				      const struct file_operations *f_ops,
@@ -379,18 +379,10 @@ void __snd_printk(unsigned int level, const char *file, int line,
  * snd_BUG_ON - debugging check macro
  * @cond: condition to evaluate
  *
- * When CONFIG_SND_DEBUG is set, this macro evaluates the given condition,
- * and call WARN() and returns the value if it's non-zero.
- * 
- * When CONFIG_SND_DEBUG is not set, this just returns zero, and the given
- * condition is ignored.
- *
- * NOTE: the argument won't be evaluated at all when CONFIG_SND_DEBUG=n.
- * Thus, don't put any statement that influences on the code behavior,
- * such as pre/post increment, to the argument of this macro.
- * If you want to evaluate and give a warning, use standard WARN_ON().
+ * Has the same behavior as WARN_ON when CONFIG_SND_DEBUG is set,
+ * otherwise just evaluates the conditional and returns the value.
  */
-#define snd_BUG_ON(cond)	WARN((cond), "BUG? (%s)\n", __stringify(cond))
+#define snd_BUG_ON(cond)	WARN_ON((cond))
 
 #else /* !CONFIG_SND_DEBUG */
 
@@ -400,11 +392,11 @@ __printf(2, 3)
 static inline void _snd_printd(int level, const char *format, ...) {}
 
 #define snd_BUG()			do { } while (0)
-static inline int __snd_bug_on(int cond)
-{
-	return 0;
-}
-#define snd_BUG_ON(cond)	__snd_bug_on(0 && (cond))  /* always false */
+
+#define snd_BUG_ON(condition) ({ \
+	int __ret_warn_on = !!(condition); \
+	unlikely(__ret_warn_on); \
+})
 
 #endif /* CONFIG_SND_DEBUG */
 
diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h
index b877334bbb0f..f11c35cd5532 100644
--- a/include/sound/dmaengine_pcm.h
+++ b/include/sound/dmaengine_pcm.h
@@ -16,6 +16,7 @@
 #define __SOUND_DMAENGINE_PCM_H__
 
 #include <sound/pcm.h>
+#include <sound/soc.h>
 #include <linux/dmaengine.h>
 
 /**
@@ -32,9 +33,6 @@ snd_pcm_substream_to_dma_direction(const struct snd_pcm_substream *substream)
 		return DMA_DEV_TO_MEM;
 }
 
-void snd_dmaengine_pcm_set_data(struct snd_pcm_substream *substream, void *data);
-void *snd_dmaengine_pcm_get_data(struct snd_pcm_substream *substream);
-
 int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream,
 	const struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config);
 int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
@@ -42,9 +40,100 @@ snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream)
 snd_pcm_uframes_t snd_dmaengine_pcm_pointer_no_residue(struct snd_pcm_substream *substream);
 
 int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
-	dma_filter_fn filter_fn, void *filter_data);
+	struct dma_chan *chan);
 int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream);
 
+int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream,
+	dma_filter_fn filter_fn, void *filter_data);
+int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream);
+
+struct dma_chan *snd_dmaengine_pcm_request_channel(dma_filter_fn filter_fn,
+	void *filter_data);
 struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream);
 
+/**
+ * struct snd_dmaengine_dai_dma_data - DAI DMA configuration data
+ * @addr: Address of the DAI data source or destination register.
+ * @addr_width: Width of the DAI data source or destination register.
+ * @maxburst: Maximum number of words(note: words, as in units of the
+ * src_addr_width member, not bytes) that can be send to or received from the
+ * DAI in one burst.
+ * @slave_id: Slave requester id for the DMA channel.
+ * @filter_data: Custom DMA channel filter data, this will usually be used when
+ * requesting the DMA channel.
+ */
+struct snd_dmaengine_dai_dma_data {
+	dma_addr_t addr;
+	enum dma_slave_buswidth addr_width;
+	u32 maxburst;
+	unsigned int slave_id;
+	void *filter_data;
+};
+
+void snd_dmaengine_pcm_set_config_from_dai_data(
+	const struct snd_pcm_substream *substream,
+	const struct snd_dmaengine_dai_dma_data *dma_data,
+	struct dma_slave_config *config);
+
+
+/*
+ * Try to request the DMA channel using compat_request_channel or
+ * compat_filter_fn if it couldn't be requested through devicetree.
+ */
+#define SND_DMAENGINE_PCM_FLAG_COMPAT BIT(0)
+/*
+ * Don't try to request the DMA channels through devicetree. This flag only
+ * makes sense if SND_DMAENGINE_PCM_FLAG_COMPAT is set as well.
+ */
+#define SND_DMAENGINE_PCM_FLAG_NO_DT BIT(1)
+/*
+ * The platforms dmaengine driver does not support reporting the amount of
+ * bytes that are still left to transfer.
+ */
+#define SND_DMAENGINE_PCM_FLAG_NO_RESIDUE BIT(2)
+/*
+ * The PCM is half duplex and the DMA channel is shared between capture and
+ * playback.
+ */
+#define SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX BIT(3)
+
+/**
+ * struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM
+ * @prepare_slave_config: Callback used to fill in the DMA slave_config for a
+ *   PCM substream. Will be called from the PCM drivers hwparams callback.
+ * @compat_request_channel: Callback to request a DMA channel for platforms
+ *   which do not use devicetree.
+ * @compat_filter_fn: Will be used as the filter function when requesting a
+ *  channel for platforms which do not use devicetree. The filter parameter
+ *  will be the DAI's DMA data.
+ * @pcm_hardware: snd_pcm_hardware struct to be used for the PCM.
+ * @prealloc_buffer_size: Size of the preallocated audio buffer.
+ *
+ * Note: If both compat_request_channel and compat_filter_fn are set
+ * compat_request_channel will be used to request the channel and
+ * compat_filter_fn will be ignored. Otherwise the channel will be requested
+ * using dma_request_channel with compat_filter_fn as the filter function.
+ */
+struct snd_dmaengine_pcm_config {
+	int (*prepare_slave_config)(struct snd_pcm_substream *substream,
+			struct snd_pcm_hw_params *params,
+			struct dma_slave_config *slave_config);
+	struct dma_chan *(*compat_request_channel)(
+			struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_substream *substream);
+	dma_filter_fn compat_filter_fn;
+
+	const struct snd_pcm_hardware *pcm_hardware;
+	unsigned int prealloc_buffer_size;
+};
+
+int snd_dmaengine_pcm_register(struct device *dev,
+	const struct snd_dmaengine_pcm_config *config,
+	unsigned int flags);
+void snd_dmaengine_pcm_unregister(struct device *dev);
+
+int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params,
+	struct dma_slave_config *slave_config);
+
 #endif
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index f841ba4bacb8..dfb42ca6d043 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -1787,6 +1787,7 @@ struct snd_emu10k1 {
 	unsigned int next_free_voice;
 
 	const struct firmware *firmware;
+	const struct firmware *dock_fw;
 
 #ifdef CONFIG_PM_SLEEP
 	unsigned int *saved_ptr;
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 5ec42dbd2308..b48792fe386b 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -181,6 +181,8 @@ struct snd_pcm_ops {
 #define SNDRV_PCM_FMTBIT_G723_24_1B	_SNDRV_PCM_FMTBIT(G723_24_1B)
 #define SNDRV_PCM_FMTBIT_G723_40	_SNDRV_PCM_FMTBIT(G723_40)
 #define SNDRV_PCM_FMTBIT_G723_40_1B	_SNDRV_PCM_FMTBIT(G723_40_1B)
+#define SNDRV_PCM_FMTBIT_DSD_U8		_SNDRV_PCM_FMTBIT(DSD_U8)
+#define SNDRV_PCM_FMTBIT_DSD_U16_LE	_SNDRV_PCM_FMTBIT(DSD_U16_LE)
 
 #ifdef SNDRV_LITTLE_ENDIAN
 #define SNDRV_PCM_FMTBIT_S16		SNDRV_PCM_FMTBIT_S16_LE
@@ -659,7 +661,7 @@ static inline snd_pcm_sframes_t snd_pcm_capture_hw_avail(struct snd_pcm_runtime
  *
  * Checks whether enough free space is available on the playback buffer.
  *
- * Returns non-zero if available, or zero if not.
+ * Return: Non-zero if available, or zero if not.
  */
 static inline int snd_pcm_playback_ready(struct snd_pcm_substream *substream)
 {
@@ -673,7 +675,7 @@ static inline int snd_pcm_playback_ready(struct snd_pcm_substream *substream)
  *
  * Checks whether enough capture data is available on the capture buffer.
  *
- * Returns non-zero if available, or zero if not.
+ * Return: Non-zero if available, or zero if not.
  */
 static inline int snd_pcm_capture_ready(struct snd_pcm_substream *substream)
 {
@@ -685,10 +687,10 @@ static inline int snd_pcm_capture_ready(struct snd_pcm_substream *substream)
  * snd_pcm_playback_data - check whether any data exists on the playback buffer
  * @substream: the pcm substream instance
  *
- * Checks whether any data exists on the playback buffer. If stop_threshold
- * is bigger or equal to boundary, then this function returns always non-zero.
+ * Checks whether any data exists on the playback buffer.
  *
- * Returns non-zero if exists, or zero if not.
+ * Return: Non-zero if any data exists, or zero if not. If stop_threshold
+ * is bigger or equal to boundary, then this function returns always non-zero.
  */
 static inline int snd_pcm_playback_data(struct snd_pcm_substream *substream)
 {
@@ -705,7 +707,7 @@ static inline int snd_pcm_playback_data(struct snd_pcm_substream *substream)
  *
  * Checks whether the playback buffer is empty.
  *
- * Returns non-zero if empty, or zero if not.
+ * Return: Non-zero if empty, or zero if not.
  */
 static inline int snd_pcm_playback_empty(struct snd_pcm_substream *substream)
 {
@@ -719,7 +721,7 @@ static inline int snd_pcm_playback_empty(struct snd_pcm_substream *substream)
  *
  * Checks whether the capture buffer is empty.
  *
- * Returns non-zero if empty, or zero if not.
+ * Return: Non-zero if empty, or zero if not.
  */
 static inline int snd_pcm_capture_empty(struct snd_pcm_substream *substream)
 {
@@ -852,7 +854,7 @@ int snd_pcm_format_big_endian(snd_pcm_format_t format);
  * snd_pcm_format_cpu_endian - Check the PCM format is CPU-endian
  * @format: the format to check
  *
- * Returns 1 if the given PCM format is CPU-endian, 0 if
+ * Return: 1 if the given PCM format is CPU-endian, 0 if
  * opposite, or a negative error code if endian not specified.
  */
 int snd_pcm_format_cpu_endian(snd_pcm_format_t format);
@@ -963,7 +965,7 @@ struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream,
  * contiguous in kernel virtual space, but not in physical memory.  Use this
  * if the buffer is accessed by kernel code but not by device DMA.
  *
- * Returns 1 if the buffer was changed, 0 if not changed, or a negative error
+ * Return: 1 if the buffer was changed, 0 if not changed, or a negative error
  * code.
  */
 static int snd_pcm_lib_alloc_vmalloc_buffer
@@ -975,6 +977,9 @@ static int snd_pcm_lib_alloc_vmalloc_buffer
  *
  * This function works like snd_pcm_lib_alloc_vmalloc_buffer(), but uses
  * vmalloc_32(), i.e., the pages are allocated from 32-bit-addressable memory.
+ *
+ * Return: 1 if the buffer was changed, 0 if not changed, or a negative error
+ * code.
  */
 static int snd_pcm_lib_alloc_vmalloc_32_buffer
 			(struct snd_pcm_substream *substream, size_t size);
@@ -1070,6 +1075,8 @@ const char *snd_pcm_format_name(snd_pcm_format_t format);
 /**
  * snd_pcm_stream_str - Get a string naming the direction of a stream
  * @substream: the pcm substream instance
+ *
+ * Return: A string naming the direction of the stream.
  */
 static inline const char *snd_pcm_stream_str(struct snd_pcm_substream *substream)
 {
@@ -1126,4 +1133,10 @@ int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream,
 			   unsigned long private_value,
 			   struct snd_pcm_chmap **info_ret);
 
+/* Strong-typed conversion of pcm_format to bitwise */
+static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format)
+{
+	return 1ULL << (__force int) pcm_format;
+}
+
 #endif /* __SOUND_PCM_H */
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 3d84808952b9..ae9a227d35d3 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -95,14 +95,6 @@ struct snd_soc_dai_driver;
 struct snd_soc_dai;
 struct snd_ac97_bus_ops;
 
-/* Digital Audio Interface registration */
-int snd_soc_register_dai(struct device *dev,
-		struct snd_soc_dai_driver *dai_drv);
-void snd_soc_unregister_dai(struct device *dev);
-int snd_soc_register_dais(struct device *dev,
-		struct snd_soc_dai_driver *dai_drv, size_t count);
-void snd_soc_unregister_dais(struct device *dev, size_t count);
-
 /* Digital Audio Interface clocking API.*/
 int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 	unsigned int freq, int dir);
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 44a30b108683..d4609029f014 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -566,7 +566,6 @@ struct snd_soc_dapm_update {
 
 /* DAPM context */
 struct snd_soc_dapm_context {
-	int n_widgets; /* number of widgets in this context */
 	enum snd_soc_bias_level bias_level;
 	enum snd_soc_bias_level suspend_bias_level;
 	struct delayed_work delayed_work;
diff --git a/include/sound/soc.h b/include/sound/soc.h
index a6a059ca3874..85c15226103b 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -324,6 +324,8 @@ struct snd_soc_dai_link;
 struct snd_soc_platform_driver;
 struct snd_soc_codec;
 struct snd_soc_codec_driver;
+struct snd_soc_component;
+struct snd_soc_component_driver;
 struct soc_enum;
 struct snd_soc_jack;
 struct snd_soc_jack_zone;
@@ -371,12 +373,20 @@ int snd_soc_suspend(struct device *dev);
 int snd_soc_resume(struct device *dev);
 int snd_soc_poweroff(struct device *dev);
 int snd_soc_register_platform(struct device *dev,
-		struct snd_soc_platform_driver *platform_drv);
+		const struct snd_soc_platform_driver *platform_drv);
 void snd_soc_unregister_platform(struct device *dev);
+int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
+		const struct snd_soc_platform_driver *platform_drv);
+void snd_soc_remove_platform(struct snd_soc_platform *platform);
+struct snd_soc_platform *snd_soc_lookup_platform(struct device *dev);
 int snd_soc_register_codec(struct device *dev,
 		const struct snd_soc_codec_driver *codec_drv,
 		struct snd_soc_dai_driver *dai_drv, int num_dai);
 void snd_soc_unregister_codec(struct device *dev);
+int snd_soc_register_component(struct device *dev,
+			 const struct snd_soc_component_driver *cmpnt_drv,
+			 struct snd_soc_dai_driver *dai_drv, int num_dai);
+void snd_soc_unregister_component(struct device *dev);
 int snd_soc_codec_volatile_register(struct snd_soc_codec *codec,
 				    unsigned int reg);
 int snd_soc_codec_readable_register(struct snd_soc_codec *codec,
@@ -801,10 +811,10 @@ struct snd_soc_platform_driver {
 		struct snd_soc_dai *);
 
 	/* platform stream pcm ops */
-	struct snd_pcm_ops *ops;
+	const struct snd_pcm_ops *ops;
 
 	/* platform stream compress ops */
-	struct snd_compr_ops *compr_ops;
+	const struct snd_compr_ops *compr_ops;
 
 	/* platform stream completion event */
 	int (*stream_event)(struct snd_soc_dapm_context *dapm, int event);
@@ -823,7 +833,7 @@ struct snd_soc_platform {
 	const char *name;
 	int id;
 	struct device *dev;
-	struct snd_soc_platform_driver *driver;
+	const struct snd_soc_platform_driver *driver;
 	struct mutex mutex;
 
 	unsigned int suspended:1; /* platform is suspended */
@@ -841,6 +851,20 @@ struct snd_soc_platform {
 #endif
 };
 
+struct snd_soc_component_driver {
+	const char *name;
+};
+
+struct snd_soc_component {
+	const char *name;
+	int id;
+	int num_dai;
+	struct device *dev;
+	struct list_head list;
+
+	const struct snd_soc_component_driver *driver;
+};
+
 struct snd_soc_dai_link {
 	/* config - must be set by machine driver */
 	const char *name;			/* Codec name */
@@ -1086,7 +1110,6 @@ struct soc_enum {
 	unsigned int mask;
 	const char * const *texts;
 	const unsigned int *values;
-	void *dapm;
 };
 
 /* codec IO */
diff --git a/include/sound/tas5086.h b/include/sound/tas5086.h
new file mode 100644
index 000000000000..aac481b7db8f
--- /dev/null
+++ b/include/sound/tas5086.h
@@ -0,0 +1,7 @@
+#ifndef _SND_SOC_CODEC_TAS5086_H_
+#define _SND_SOC_CODEC_TAS5086_H_
+
+#define TAS5086_CLK_IDX_MCLK	0
+#define TAS5086_CLK_IDX_SCLK	1
+
+#endif /* _SND_SOC_CODEC_TAS5086_H_ */
diff --git a/include/sound/tegra_wm8903.h b/include/sound/tegra_wm8903.h
deleted file mode 100644
index 57b202ee97c3..000000000000
--- a/include/sound/tegra_wm8903.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2011 NVIDIA, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- */
-
-#ifndef __SOUND_TEGRA_WM38903_H
-#define __SOUND_TEGRA_WM38903_H
-
-struct tegra_wm8903_platform_data {
-	int gpio_spkr_en;
-	int gpio_hp_det;
-	int gpio_hp_mute;
-	int gpio_int_mic_en;
-	int gpio_ext_mic_en;
-};
-
-#endif
diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
index 1774a5c3ef10..e3983d508272 100644
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
@@ -214,7 +214,9 @@ typedef int __bitwise snd_pcm_format_t;
 #define	SNDRV_PCM_FORMAT_G723_24_1B	((__force snd_pcm_format_t) 45) /* 1 sample in 1 byte */
 #define	SNDRV_PCM_FORMAT_G723_40	((__force snd_pcm_format_t) 46) /* 8 Samples in 5 bytes */
 #define	SNDRV_PCM_FORMAT_G723_40_1B	((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */
-#define	SNDRV_PCM_FORMAT_LAST		SNDRV_PCM_FORMAT_G723_40_1B
+#define	SNDRV_PCM_FORMAT_DSD_U8		((__force snd_pcm_format_t) 48) /* DSD, 1-byte samples DSD (x8) */
+#define	SNDRV_PCM_FORMAT_DSD_U16_LE	((__force snd_pcm_format_t) 49) /* DSD, 2-byte samples DSD (x16), little endian */
+#define	SNDRV_PCM_FORMAT_LAST		SNDRV_PCM_FORMAT_DSD_U16_LE
 
 #ifdef SNDRV_LITTLE_ENDIAN
 #define	SNDRV_PCM_FORMAT_S16		SNDRV_PCM_FORMAT_S16_LE
diff --git a/sound/aoa/soundbus/i2sbus/pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c
index 19491ed9292f..7b74a4ba75f8 100644
--- a/sound/aoa/soundbus/i2sbus/pcm.c
+++ b/sound/aoa/soundbus/i2sbus/pcm.c
@@ -179,7 +179,7 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
 	 */
 	if (other->active) {
 		/* FIXME: is this guaranteed by the alsa api? */
-		hw->formats &= (1ULL << i2sdev->format);
+		hw->formats &= pcm_format_to_bits(i2sdev->format);
 		/* see above, restrict rates to the one we already have */
 		hw->rate_min = i2sdev->rate;
 		hw->rate_max = i2sdev->rate;
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
index 79d6bda58753..6b7e2b5a72de 100644
--- a/sound/atmel/ac97c.c
+++ b/sound/atmel/ac97c.c
@@ -182,7 +182,7 @@ static int atmel_ac97c_playback_open(struct snd_pcm_substream *substream)
 		runtime->hw.rate_max = chip->cur_rate;
 	}
 	if (chip->cur_format)
-		runtime->hw.formats = (1ULL << chip->cur_format);
+		runtime->hw.formats = pcm_format_to_bits(chip->cur_format);
 	mutex_unlock(&opened_mutex);
 	chip->playback_substream = substream;
 	return 0;
@@ -201,7 +201,7 @@ static int atmel_ac97c_capture_open(struct snd_pcm_substream *substream)
 		runtime->hw.rate_max = chip->cur_rate;
 	}
 	if (chip->cur_format)
-		runtime->hw.formats = (1ULL << chip->cur_format);
+		runtime->hw.formats = pcm_format_to_bits(chip->cur_format);
 	mutex_unlock(&opened_mutex);
 	chip->capture_substream = substream;
 	return 0;
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index c84abc886e90..99db892d7299 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -28,11 +28,13 @@
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/list.h>
+#include <linux/math64.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
 #include <linux/poll.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
+#include <linux/types.h>
 #include <linux/uio.h>
 #include <linux/uaccess.h>
 #include <linux/module.h>
@@ -152,26 +154,23 @@ static int snd_compr_update_tstamp(struct snd_compr_stream *stream,
 	stream->ops->pointer(stream, tstamp);
 	pr_debug("dsp consumed till %d total %d bytes\n",
 		tstamp->byte_offset, tstamp->copied_total);
-	stream->runtime->hw_pointer = tstamp->byte_offset;
-	stream->runtime->total_bytes_transferred = tstamp->copied_total;
+	if (stream->direction == SND_COMPRESS_PLAYBACK)
+		stream->runtime->total_bytes_transferred = tstamp->copied_total;
+	else
+		stream->runtime->total_bytes_available = tstamp->copied_total;
 	return 0;
 }
 
 static size_t snd_compr_calc_avail(struct snd_compr_stream *stream,
 		struct snd_compr_avail *avail)
 {
-	long avail_calc; /*this needs to be signed variable */
-
 	memset(avail, 0, sizeof(*avail));
 	snd_compr_update_tstamp(stream, &avail->tstamp);
 	/* Still need to return avail even if tstamp can't be filled in */
 
-	/* FIXME: This needs to be different for capture stream,
-	   available is # of compressed data, for playback it's
-	   remainder of buffer */
-
 	if (stream->runtime->total_bytes_available == 0 &&
-			stream->runtime->state == SNDRV_PCM_STATE_SETUP) {
+			stream->runtime->state == SNDRV_PCM_STATE_SETUP &&
+			stream->direction == SND_COMPRESS_PLAYBACK) {
 		pr_debug("detected init and someone forgot to do a write\n");
 		return stream->runtime->buffer_size;
 	}
@@ -180,26 +179,22 @@ static size_t snd_compr_calc_avail(struct snd_compr_stream *stream,
 			stream->runtime->total_bytes_transferred);
 	if (stream->runtime->total_bytes_available ==
 				stream->runtime->total_bytes_transferred) {
-		pr_debug("both pointers are same, returning full avail\n");
-		return stream->runtime->buffer_size;
+		if (stream->direction == SND_COMPRESS_PLAYBACK) {
+			pr_debug("both pointers are same, returning full avail\n");
+			return stream->runtime->buffer_size;
+		} else {
+			pr_debug("both pointers are same, returning no avail\n");
+			return 0;
+		}
 	}
 
-	/* FIXME: this routine isn't consistent, in one test we use
-	 * cumulative values and in the other byte offsets. Do we
-	 * really need the byte offsets if the cumulative values have
-	 * been updated? In the PCM interface app_ptr and hw_ptr are
-	 * already cumulative */
+	avail->avail = stream->runtime->total_bytes_available -
+			stream->runtime->total_bytes_transferred;
+	if (stream->direction == SND_COMPRESS_PLAYBACK)
+		avail->avail = stream->runtime->buffer_size - avail->avail;
 
-	avail_calc = stream->runtime->buffer_size -
-		(stream->runtime->app_pointer - stream->runtime->hw_pointer);
-	pr_debug("calc avail as %ld, app_ptr %lld, hw+ptr %lld\n", avail_calc,
-			stream->runtime->app_pointer,
-			stream->runtime->hw_pointer);
-	if (avail_calc >= stream->runtime->buffer_size)
-		avail_calc -= stream->runtime->buffer_size;
-	pr_debug("ret avail as %ld\n", avail_calc);
-	avail->avail = avail_calc;
-	return avail_calc;
+	pr_debug("ret avail as %lld\n", avail->avail);
+	return avail->avail;
 }
 
 static inline size_t snd_compr_get_avail(struct snd_compr_stream *stream)
@@ -230,21 +225,24 @@ static int snd_compr_write_data(struct snd_compr_stream *stream,
 	void *dstn;
 	size_t copy;
 	struct snd_compr_runtime *runtime = stream->runtime;
+	/* 64-bit Modulus */
+	u64 app_pointer = div64_u64(runtime->total_bytes_available,
+				    runtime->buffer_size);
+	app_pointer = runtime->total_bytes_available -
+		      (app_pointer * runtime->buffer_size);
 
-	dstn = runtime->buffer + runtime->app_pointer;
+	dstn = runtime->buffer + app_pointer;
 	pr_debug("copying %ld at %lld\n",
-			(unsigned long)count, runtime->app_pointer);
-	if (count < runtime->buffer_size - runtime->app_pointer) {
+			(unsigned long)count, app_pointer);
+	if (count < runtime->buffer_size - app_pointer) {
 		if (copy_from_user(dstn, buf, count))
 			return -EFAULT;
-		runtime->app_pointer += count;
 	} else {
-		copy = runtime->buffer_size - runtime->app_pointer;
+		copy = runtime->buffer_size - app_pointer;
 		if (copy_from_user(dstn, buf, copy))
 			return -EFAULT;
 		if (copy_from_user(runtime->buffer, buf + copy, count - copy))
 			return -EFAULT;
-		runtime->app_pointer = count - copy;
 	}
 	/* if DSP cares, let it know data has been written */
 	if (stream->ops->ack)
@@ -278,10 +276,12 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf,
 	if (avail > count)
 		avail = count;
 
-	if (stream->ops->copy)
-		retval = stream->ops->copy(stream, buf, avail);
-	else
+	if (stream->ops->copy) {
+		char __user* cbuf = (char __user*)buf;
+		retval = stream->ops->copy(stream, cbuf, avail);
+	} else {
 		retval = snd_compr_write_data(stream, buf, avail);
+	}
 	if (retval > 0)
 		stream->runtime->total_bytes_available += retval;
 
@@ -300,7 +300,49 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf,
 static ssize_t snd_compr_read(struct file *f, char __user *buf,
 		size_t count, loff_t *offset)
 {
-	return -ENXIO;
+	struct snd_compr_file *data = f->private_data;
+	struct snd_compr_stream *stream;
+	size_t avail;
+	int retval;
+
+	if (snd_BUG_ON(!data))
+		return -EFAULT;
+
+	stream = &data->stream;
+	mutex_lock(&stream->device->lock);
+
+	/* read is allowed when stream is running, paused, draining and setup
+	 * (yes setup is state which we transition to after stop, so if user
+	 * wants to read data after stop we allow that)
+	 */
+	switch (stream->runtime->state) {
+	case SNDRV_PCM_STATE_OPEN:
+	case SNDRV_PCM_STATE_PREPARED:
+	case SNDRV_PCM_STATE_XRUN:
+	case SNDRV_PCM_STATE_SUSPENDED:
+	case SNDRV_PCM_STATE_DISCONNECTED:
+		retval = -EBADFD;
+		goto out;
+	}
+
+	avail = snd_compr_get_avail(stream);
+	pr_debug("avail returned %ld\n", (unsigned long)avail);
+	/* calculate how much we can read from buffer */
+	if (avail > count)
+		avail = count;
+
+	if (stream->ops->copy) {
+		retval = stream->ops->copy(stream, buf, avail);
+	} else {
+		retval = -ENXIO;
+		goto out;
+	}
+	if (retval > 0)
+		stream->runtime->total_bytes_transferred += retval;
+
+out:
+	mutex_unlock(&stream->device->lock);
+	return retval;
 }
 
 static int snd_compr_mmap(struct file *f, struct vm_area_struct *vma)
@@ -375,6 +417,7 @@ snd_compr_get_caps(struct snd_compr_stream *stream, unsigned long arg)
 	if (!stream->ops->get_caps)
 		return -ENXIO;
 
+	memset(&caps, 0, sizeof(caps));
 	retval = stream->ops->get_caps(stream, &caps);
 	if (retval)
 		goto out;
@@ -393,7 +436,7 @@ snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)
 	if (!stream->ops->get_codec_caps)
 		return -ENXIO;
 
-	caps = kmalloc(sizeof(*caps), GFP_KERNEL);
+	caps = kzalloc(sizeof(*caps), GFP_KERNEL);
 	if (!caps)
 		return -ENOMEM;
 
@@ -485,9 +528,14 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
 		retval = stream->ops->set_params(stream, params);
 		if (retval)
 			goto out;
-		stream->runtime->state = SNDRV_PCM_STATE_SETUP;
+
 		stream->metadata_set = false;
 		stream->next_track = false;
+
+		if (stream->direction == SND_COMPRESS_PLAYBACK)
+			stream->runtime->state = SNDRV_PCM_STATE_SETUP;
+		else
+			stream->runtime->state = SNDRV_PCM_STATE_PREPARED;
 	} else {
 		return -EPERM;
 	}
@@ -505,7 +553,7 @@ snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg)
 	if (!stream->ops->get_params)
 		return -EBADFD;
 
-	params = kmalloc(sizeof(*params), GFP_KERNEL);
+	params = kzalloc(sizeof(*params), GFP_KERNEL);
 	if (!params)
 		return -ENOMEM;
 	retval = stream->ops->get_params(stream, params);
@@ -622,8 +670,6 @@ static int snd_compr_stop(struct snd_compr_stream *stream)
 	if (!retval) {
 		stream->runtime->state = SNDRV_PCM_STATE_SETUP;
 		wake_up(&stream->runtime->sleep);
-		stream->runtime->hw_pointer = 0;
-		stream->runtime->app_pointer = 0;
 		stream->runtime->total_bytes_available = 0;
 		stream->runtime->total_bytes_transferred = 0;
 	}
diff --git a/sound/core/control.c b/sound/core/control.c
index 8c7c2c9bba61..d8aa206e8bde 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -190,7 +190,7 @@ EXPORT_SYMBOL(snd_ctl_notify);
  * Allocates a new struct snd_kcontrol instance and copies the given template 
  * to the new instance. It does not copy volatile data (access).
  *
- * Returns the pointer of the new instance, or NULL on failure.
+ * Return: The pointer of the new instance, or %NULL on failure.
  */
 static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control,
 					unsigned int access)
@@ -224,7 +224,7 @@ static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control,
  * template.  When the access field of ncontrol is 0, it's assumed as
  * READWRITE access. When the count field is 0, it's assumes as one.
  *
- * Returns the pointer of the newly generated instance, or NULL on failure.
+ * Return: The pointer of the newly generated instance, or %NULL on failure.
  */
 struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
 				  void *private_data)
@@ -322,9 +322,10 @@ static int snd_ctl_find_hole(struct snd_card *card, unsigned int count)
  * snd_ctl_new1() to the given card. Assigns also an unique
  * numid used for fast search.
  *
- * Returns zero if successful, or a negative error code on failure.
- *
  * It frees automatically the control which cannot be added.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
+ *
  */
 int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
 {
@@ -380,9 +381,9 @@ EXPORT_SYMBOL(snd_ctl_add);
  * 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.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
 		    bool add_on_replace)
@@ -442,8 +443,8 @@ EXPORT_SYMBOL(snd_ctl_replace);
  * Removes the control from the card and then releases the instance.
  * You don't need to call snd_ctl_free_one(). You must be in
  * the write lock - down_write(&card->controls_rwsem).
- * 
- * Returns 0 if successful, or a negative error code on failure.
+ *
+ * Return: 0 if successful, or a negative error code on failure.
  */
 int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol)
 {
@@ -470,8 +471,8 @@ EXPORT_SYMBOL(snd_ctl_remove);
  *
  * Finds the control instance with the given id, removes it from the
  * card list and releases it.
- * 
- * Returns 0 if successful, or a negative error code on failure.
+ *
+ * Return: 0 if successful, or a negative error code on failure.
  */
 int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id)
 {
@@ -498,8 +499,8 @@ EXPORT_SYMBOL(snd_ctl_remove_id);
  *
  * Finds the control instance with the given id, removes it from the
  * card list and releases it.
- * 
- * Returns 0 if successful, or a negative error code on failure.
+ *
+ * Return: 0 if successful, or a negative error code on failure.
  */
 static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file,
 				   struct snd_ctl_elem_id *id)
@@ -541,7 +542,7 @@ error:
  * Finds the control instance with the given id, and activate or
  * inactivate the control together with notification, if changed.
  *
- * Returns 0 if unchanged, 1 if changed, or a negative error code on failure.
+ * Return: 0 if unchanged, 1 if changed, or a negative error code on failure.
  */
 int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
 			int active)
@@ -587,7 +588,7 @@ EXPORT_SYMBOL_GPL(snd_ctl_activate_id);
  * Finds the control with the old id from the card, and replaces the
  * id with the new one.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
 		      struct snd_ctl_elem_id *dst_id)
@@ -616,10 +617,11 @@ EXPORT_SYMBOL(snd_ctl_rename_id);
  *
  * Finds the control instance with the given number-id from the card.
  *
- * Returns the pointer of the instance if found, or NULL if not.
- *
  * The caller must down card->controls_rwsem before calling this function
  * (if the race condition can happen).
+ *
+ * Return: The pointer of the instance if found, or %NULL if not.
+ *
  */
 struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid)
 {
@@ -643,10 +645,11 @@ EXPORT_SYMBOL(snd_ctl_find_numid);
  *
  * Finds the control instance with the given id from the card.
  *
- * Returns the pointer of the instance if found, or NULL if not.
- *
  * The caller must down card->controls_rwsem before calling this function
  * (if the race condition can happen).
+ *
+ * Return: The pointer of the instance if found, or %NULL if not.
+ *
  */
 struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
 				     struct snd_ctl_elem_id *id)
@@ -1710,6 +1713,8 @@ EXPORT_SYMBOL(snd_ctl_boolean_stereo_info);
  * Sets all required fields in @info to their appropriate values.
  * If the control's accessibility is not the default (readable and writable),
  * the caller has to fill @info->access.
+ *
+ * Return: Zero.
  */
 int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels,
 		      unsigned int items, const char *const names[])
diff --git a/sound/core/device.c b/sound/core/device.c
index f03cb5444a5a..df88defed176 100644
--- a/sound/core/device.c
+++ b/sound/core/device.c
@@ -39,7 +39,7 @@
  * The data pointer plays a role as the identifier, too, so the
  * pointer address must be unique and unchanged.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_device_new(struct snd_card *card, snd_device_type_t type,
 		   void *device_data, struct snd_device_ops *ops)
@@ -73,7 +73,7 @@ EXPORT_SYMBOL(snd_device_new);
  * callbacks, dev_disconnect and dev_free, corresponding to the state.
  * Then release the device.
  *
- * Returns zero if successful, or a negative error code on failure or if the
+ * Return: Zero if successful, or a negative error code on failure or if the
  * device not found.
  */
 int snd_device_free(struct snd_card *card, void *device_data)
@@ -116,7 +116,7 @@ EXPORT_SYMBOL(snd_device_free);
  *
  * Usually called from snd_card_disconnect().
  *
- * Returns zero if successful, or a negative error code on failure or if the
+ * Return: Zero if successful, or a negative error code on failure or if the
  * device not found.
  */
 int snd_device_disconnect(struct snd_card *card, void *device_data)
@@ -151,7 +151,7 @@ int snd_device_disconnect(struct snd_card *card, void *device_data)
  * but it can be called later if any new devices are created after
  * invocation of snd_card_register().
  *
- * Returns zero if successful, or a negative error code on failure or if the
+ * Return: Zero if successful, or a negative error code on failure or if the
  * device not found.
  */
 int snd_device_register(struct snd_card *card, void *device_data)
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 3f7f6628cf7b..d105073298cb 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -356,7 +356,7 @@ static const struct file_operations snd_hwdep_f_ops =
  * The callbacks (hwdep->ops) must be set on the returned instance
  * after this call manually by the caller.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_hwdep_new(struct snd_card *card, char *id, int device,
 		  struct snd_hwdep **rhwdep)
diff --git a/sound/core/info.c b/sound/core/info.c
index 3c9bd6b10a96..e79baa11b60e 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -89,7 +89,7 @@ static int resize_info_buffer(struct snd_info_buffer *buffer,
 	char *nbuf;
 
 	nsize = PAGE_ALIGN(nsize);
-	nbuf = krealloc(buffer->buffer, nsize, GFP_KERNEL);
+	nbuf = krealloc(buffer->buffer, nsize, GFP_KERNEL | __GFP_ZERO);
 	if (! nbuf)
 		return -ENOMEM;
 
@@ -105,7 +105,7 @@ static int resize_info_buffer(struct snd_info_buffer *buffer,
  *
  * Outputs the string on the procfs buffer just like printf().
  *
- * Returns the size of output string.
+ * Return: The size of output string, or a negative error code.
  */
 int snd_iprintf(struct snd_info_buffer *buffer, const char *fmt, ...)
 {
@@ -344,7 +344,7 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
 				goto __nomem;
 			data->rbuffer = buffer;
 			buffer->len = PAGE_SIZE;
-			buffer->buffer = kmalloc(buffer->len, GFP_KERNEL);
+			buffer->buffer = kzalloc(buffer->len, GFP_KERNEL);
 			if (buffer->buffer == NULL)
 				goto __nomem;
 		}
@@ -683,32 +683,27 @@ int snd_info_card_free(struct snd_card *card)
  *
  * Reads one line from the buffer and stores the string.
  *
- * Returns zero if successful, or 1 if error or EOF.
+ * Return: Zero if successful, or 1 if error or EOF.
  */
 int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len)
 {
 	int c = -1;
 
+	if (snd_BUG_ON(!buffer || !buffer->buffer))
+		return 1;
 	if (len <= 0 || buffer->stop || buffer->error)
 		return 1;
-	while (--len > 0) {
+	while (!buffer->stop) {
 		c = buffer->buffer[buffer->curr++];
-		if (c == '\n') {
-			if (buffer->curr >= buffer->size)
-				buffer->stop = 1;
-			break;
-		}
-		*line++ = c;
-		if (buffer->curr >= buffer->size) {
+		if (buffer->curr >= buffer->size)
 			buffer->stop = 1;
+		if (c == '\n')
 			break;
+		if (len) {
+			len--;
+			*line++ = c;
 		}
 	}
-	while (c != '\n' && !buffer->stop) {
-		c = buffer->buffer[buffer->curr++];
-		if (buffer->curr >= buffer->size)
-			buffer->stop = 1;
-	}
 	*line = '\0';
 	return 0;
 }
@@ -724,7 +719,7 @@ EXPORT_SYMBOL(snd_info_get_line);
  * Parses the original string and copy a token to the given
  * string buffer.
  *
- * Returns the updated pointer of the original string so that
+ * Return: The updated pointer of the original string so that
  * it can be used for the next call.
  */
 const char *snd_info_get_str(char *dest, const char *src, int len)
@@ -763,7 +758,7 @@ EXPORT_SYMBOL(snd_info_get_str);
  * Usually called from other functions such as
  * snd_info_create_card_entry().
  *
- * Returns the pointer of the new instance, or NULL on failure.
+ * Return: The pointer of the new instance, or %NULL on failure.
  */
 static struct snd_info_entry *snd_info_create_entry(const char *name)
 {
@@ -792,7 +787,7 @@ static struct snd_info_entry *snd_info_create_entry(const char *name)
  *
  * Creates a new info entry and assigns it to the given module.
  *
- * Returns the pointer of the new instance, or NULL on failure.
+ * Return: The pointer of the new instance, or %NULL on failure.
  */
 struct snd_info_entry *snd_info_create_module_entry(struct module * module,
 					       const char *name,
@@ -816,7 +811,7 @@ EXPORT_SYMBOL(snd_info_create_module_entry);
  *
  * Creates a new info entry and assigns it to the given card.
  *
- * Returns the pointer of the new instance, or NULL on failure.
+ * Return: The pointer of the new instance, or %NULL on failure.
  */
 struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card,
 					     const char *name,
@@ -882,7 +877,7 @@ static int snd_info_dev_register_entry(struct snd_device *device)
  * For releasing this entry, use snd_device_free() instead of
  * snd_info_free_entry(). 
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_card_proc_new(struct snd_card *card, const char *name,
 		      struct snd_info_entry **entryp)
@@ -938,7 +933,7 @@ EXPORT_SYMBOL(snd_info_free_entry);
  *
  * Registers the proc info entry.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_info_register(struct snd_info_entry * entry)
 {
diff --git a/sound/core/init.c b/sound/core/init.c
index 7b012d15c2cf..6ef06400dfc8 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -144,7 +144,7 @@ static inline int init_info_for_card(struct snd_card *card)
  *  space for the driver to use freely.  The allocated struct is stored
  *  in the given card_ret pointer.
  *
- *  Returns zero if successful or a negative error code.
+ *  Return: Zero if successful or a negative error code.
  */
 int snd_card_create(int idx, const char *xid,
 		    struct module *module, int extra_size,
@@ -337,7 +337,7 @@ static const struct file_operations snd_shutdown_f_ops =
  *
  *  Disconnects all APIs from the file-operations (user space).
  *
- *  Returns zero, otherwise a negative error code.
+ *  Return: Zero, otherwise a negative error code.
  *
  *  Note: The current implementation replaces all active file->f_op with special
  *        dummy file operations (they do nothing except release).
@@ -415,7 +415,7 @@ EXPORT_SYMBOL(snd_card_disconnect);
  *  devices automatically.  That is, you don't have to release the devices
  *  by yourself.
  *
- *  Returns zero. Frees all associated devices and frees the control
+ *  Return: Zero. Frees all associated devices and frees the control
  *  interface associated to given soundcard.
  */
 static int snd_card_do_free(struct snd_card *card)
@@ -677,7 +677,7 @@ static struct device_attribute card_number_attrs =
  *  external accesses.  Thus, you should call this function at the end
  *  of the initialization of the card.
  *
- *  Returns zero otherwise a negative error code if the registration failed.
+ *  Return: Zero otherwise a negative error code if the registration failed.
  */
 int snd_card_register(struct snd_card *card)
 {
@@ -849,7 +849,7 @@ int __exit snd_card_info_done(void)
  *  This function adds the component id string to the supported list.
  *  The component can be referred from the alsa-lib.
  *
- *  Returns zero otherwise a negative error code.
+ *  Return: Zero otherwise a negative error code.
  */
   
 int snd_component_add(struct snd_card *card, const char *component)
@@ -883,7 +883,7 @@ EXPORT_SYMBOL(snd_component_add);
  *  This linked-list is used to keep tracking the connection state,
  *  and to avoid the release of busy resources by hotplug.
  *
- *  Returns zero or a negative error code.
+ *  Return: zero or a negative error code.
  */
 int snd_card_file_add(struct snd_card *card, struct file *file)
 {
@@ -920,7 +920,7 @@ EXPORT_SYMBOL(snd_card_file_add);
  *  called beforehand, it processes the pending release of
  *  resources.
  *
- *  Returns zero or a negative error code.
+ *  Return: Zero or a negative error code.
  */
 int snd_card_file_remove(struct snd_card *card, struct file *file)
 {
@@ -959,6 +959,8 @@ EXPORT_SYMBOL(snd_card_file_remove);
  *
  *  Waits until the power-state is changed.
  *
+ *  Return: Zero if successful, or a negative error code.
+ *
  *  Note: the power lock must be active before call.
  */
 int snd_power_wait(struct snd_card *card, unsigned int power_state)
diff --git a/sound/core/isadma.c b/sound/core/isadma.c
index c0f1208bb7df..e2b386156a4c 100644
--- a/sound/core/isadma.c
+++ b/sound/core/isadma.c
@@ -81,7 +81,7 @@ EXPORT_SYMBOL(snd_dma_disable);
  * @dma: the dma number
  * @size: the dma transfer size
  *
- * Returns the current pointer in DMA tranfer buffer in bytes
+ * Return: The current pointer in DMA transfer buffer in bytes.
  */
 unsigned int snd_dma_pointer(unsigned long dma, unsigned int size)
 {
diff --git a/sound/core/jack.c b/sound/core/jack.c
index a06b1651fcba..b35fe7345c20 100644
--- a/sound/core/jack.c
+++ b/sound/core/jack.c
@@ -98,8 +98,8 @@ static int snd_jack_dev_register(struct snd_device *device)
  *
  * Creates a new jack object.
  *
- * Returns zero if successful, or a negative error code on failure.
- * On success jjack will be initialised.
+ * Return: Zero if successful, or a negative error code on failure.
+ * On success @jjack will be initialised.
  */
 int snd_jack_new(struct snd_card *card, const char *id, int type,
 		 struct snd_jack **jjack)
@@ -189,6 +189,8 @@ EXPORT_SYMBOL(snd_jack_set_parent);
  * using this abstraction.
  *
  * This function may only be called prior to registration of the jack.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_jack_set_key(struct snd_jack *jack, enum snd_jack_types type,
 		     int keytype)
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index 691569238435..bdf826f4fe0c 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -81,7 +81,7 @@ static inline void dec_snd_pages(int order)
  *
  * Allocates the physically contiguous pages with the given size.
  *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
+ * Return: The pointer of the buffer, or %NULL if no enough memory.
  */
 void *snd_malloc_pages(size_t size, gfp_t gfp_flags)
 {
@@ -175,9 +175,9 @@ static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr,
  *
  * Calls the memory-allocator function for the corresponding
  * buffer type.
- * 
- * Returns zero if the buffer with the given size is allocated successfully,
- * other a negative value at error.
+ *
+ * Return: Zero if the buffer with the given size is allocated successfully,
+ * otherwise a negative value on error.
  */
 int snd_dma_alloc_pages(int type, struct device *device, size_t size,
 			struct snd_dma_buffer *dmab)
@@ -229,9 +229,9 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
  * buffer type.  When no space is left, this function reduces the size and
  * tries to allocate again.  The size actually allocated is stored in
  * res_size argument.
- * 
- * Returns zero if the buffer with the given size is allocated successfully,
- * other a negative value at error.
+ *
+ * Return: Zero if the buffer with the given size is allocated successfully,
+ * otherwise a negative value on error.
  */
 int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size,
 				 struct snd_dma_buffer *dmab)
@@ -292,7 +292,7 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
  * Looks for the reserved-buffer list and re-uses if the same buffer
  * is found in the list.  When the buffer is found, it's removed from the free list.
  *
- * Returns the size of buffer if the buffer is found, or zero if not found.
+ * Return: The size of buffer if the buffer is found, or zero if not found.
  */
 size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id)
 {
@@ -326,8 +326,8 @@ size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id)
  * @id: the buffer id
  *
  * Reserves the given buffer as a reserved buffer.
- * 
- * Returns zero if successful, or a negative code at error.
+ *
+ * Return: Zero if successful, or a negative code on error.
  */
 int snd_dma_reserve_buf(struct snd_dma_buffer *dmab, unsigned int id)
 {
diff --git a/sound/core/memory.c b/sound/core/memory.c
index 66a278d0b04e..36c0f1a2e189 100644
--- a/sound/core/memory.c
+++ b/sound/core/memory.c
@@ -33,7 +33,7 @@
  *
  * Copies the data from mmio-space to user-space.
  *
- * Returns zero if successful, or non-zero on failure.
+ * Return: Zero if successful, or non-zero on failure.
  */
 int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size_t count)
 {
@@ -66,7 +66,7 @@ EXPORT_SYMBOL(copy_to_user_fromio);
  *
  * Copies the data from user-space to mmio-space.
  *
- * Returns zero if successful, or non-zero on failure.
+ * Return: Zero if successful, or non-zero on failure.
  */
 int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size_t count)
 {
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 61798f85d030..17f45e8aa89c 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -209,6 +209,8 @@ static char *snd_pcm_format_names[] = {
 	FORMAT(G723_24_1B),
 	FORMAT(G723_40),
 	FORMAT(G723_40_1B),
+	FORMAT(DSD_U8),
+	FORMAT(DSD_U16_LE),
 };
 
 const char *snd_pcm_format_name(snd_pcm_format_t format)
@@ -637,7 +639,7 @@ static inline int snd_pcm_substream_proc_done(struct snd_pcm_substream *substrea
  * calling this, i.e. zero must be given to the argument of
  * snd_pcm_new().
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
 {
@@ -759,7 +761,7 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
  * The pcm operators have to be set afterwards to the new instance
  * via snd_pcm_set_ops().
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_new(struct snd_card *card, const char *id, int device,
 		int playback_count, int capture_count, struct snd_pcm **rpcm)
@@ -787,7 +789,7 @@ EXPORT_SYMBOL(snd_pcm_new);
  * The pcm operators have to be set afterwards to the new instance
  * via snd_pcm_set_ops().
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_new_internal(struct snd_card *card, const char *id, int device,
 	int playback_count, int capture_count,
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index c4840ff75d00..41b3dfe68698 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -666,7 +666,8 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b,
  * The interval is changed to the range satisfying both intervals.
  * The interval status (min, max, integer, etc.) are evaluated.
  *
- * Returns non-zero if the value is changed, zero if not changed.
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
  */
 int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v)
 {
@@ -865,7 +866,8 @@ void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k,
  * @nump: pointer to store the resultant numerator
  * @denp: pointer to store the resultant denominator
  *
- * Returns non-zero if the value is changed, zero if not changed.
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
  */
 int snd_interval_ratnum(struct snd_interval *i,
 			unsigned int rats_count, struct snd_ratnum *rats,
@@ -983,7 +985,8 @@ EXPORT_SYMBOL(snd_interval_ratnum);
  * @nump: pointer to store the resultant numerator
  * @denp: pointer to store the resultant denominator
  *
- * Returns non-zero if the value is changed, zero if not changed.
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
  */
 static int snd_interval_ratden(struct snd_interval *i,
 			       unsigned int rats_count, struct snd_ratden *rats,
@@ -1082,7 +1085,8 @@ static int snd_interval_ratden(struct snd_interval *i,
  * When mask is non-zero, only the elements corresponding to bit 1 are
  * evaluated.
  *
- * Returns non-zero if the value is changed, zero if not changed.
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
  */
 int snd_interval_list(struct snd_interval *i, unsigned int count,
 		      const unsigned int *list, unsigned int mask)
@@ -1142,7 +1146,7 @@ static int snd_interval_step(struct snd_interval *i, unsigned int min, unsigned
  * @private: the private data pointer passed to function
  * @dep: the dependent variables
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond,
 			int var,
@@ -1200,6 +1204,8 @@ EXPORT_SYMBOL(snd_pcm_hw_rule_add);
  * @mask: the bitmap mask
  *
  * Apply the constraint of the given bitmap mask to a 32-bit mask parameter.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
 			       u_int32_t mask)
@@ -1220,6 +1226,8 @@ int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, snd_pcm_hw_param
  * @mask: the 64bit bitmap mask
  *
  * Apply the constraint of the given bitmap mask to a 64-bit mask parameter.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
 				 u_int64_t mask)
@@ -1240,6 +1248,9 @@ int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_par
  * @var: hw_params variable to apply the integer constraint
  *
  * Apply the constraint of integer to an interval parameter.
+ *
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
  */
 int snd_pcm_hw_constraint_integer(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var)
 {
@@ -1257,6 +1268,9 @@ EXPORT_SYMBOL(snd_pcm_hw_constraint_integer);
  * @max: the maximal value
  * 
  * Apply the min/max range constraint to an interval parameter.
+ *
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
  */
 int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
 				 unsigned int min, unsigned int max)
@@ -1288,6 +1302,8 @@ static int snd_pcm_hw_rule_list(struct snd_pcm_hw_params *params,
  * @l: list
  * 
  * Apply the list of constraints to an interval parameter.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime,
 			       unsigned int cond,
@@ -1322,6 +1338,8 @@ static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params,
  * @cond: condition bits
  * @var: hw_params variable to apply the ratnums constraint
  * @r: struct snd_ratnums constriants
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, 
 				  unsigned int cond,
@@ -1355,6 +1373,8 @@ static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params,
  * @cond: condition bits
  * @var: hw_params variable to apply the ratdens constraint
  * @r: struct snd_ratdens constriants
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime, 
 				  unsigned int cond,
@@ -1386,6 +1406,8 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,
  * @cond: condition bits
  * @width: sample bits width
  * @msbits: msbits width
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime, 
 				 unsigned int cond,
@@ -1414,6 +1436,8 @@ static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params,
  * @cond: condition bits
  * @var: hw_params variable to apply the step constraint
  * @step: step size
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime,
 			       unsigned int cond,
@@ -1444,6 +1468,8 @@ static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm
  * @runtime: PCM runtime instance
  * @cond: condition bits
  * @var: hw_params variable to apply the power-of-2 constraint
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime,
 			       unsigned int cond,
@@ -1470,6 +1496,8 @@ static int snd_pcm_hw_rule_noresample_func(struct snd_pcm_hw_params *params,
  * snd_pcm_hw_rule_noresample - add a rule to allow disabling hw resampling
  * @runtime: PCM runtime instance
  * @base_rate: the rate at which the hardware does not resample
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_rule_noresample(struct snd_pcm_runtime *runtime,
 			       unsigned int base_rate)
@@ -1519,8 +1547,8 @@ EXPORT_SYMBOL(_snd_pcm_hw_params_any);
  * @var: parameter to retrieve
  * @dir: pointer to the direction (-1,0,1) or %NULL
  *
- * Return the value for field @var if it's fixed in configuration space
- * defined by @params. Return -%EINVAL otherwise.
+ * Return: The value for field @var if it's fixed in configuration space
+ * defined by @params. -%EINVAL otherwise.
  */
 int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,
 			   snd_pcm_hw_param_t var, int *dir)
@@ -1591,7 +1619,8 @@ static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params,
  *
  * Inside configuration space defined by @params remove from @var all
  * values > minimum. Reduce configuration space accordingly.
- * Return the minimum.
+ *
+ * Return: The minimum, or a negative error code on failure.
  */
 int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm, 
 			   struct snd_pcm_hw_params *params, 
@@ -1637,7 +1666,8 @@ static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params,
  *
  * Inside configuration space defined by @params remove from @var all
  * values < maximum. Reduce configuration space accordingly.
- * Return the maximum.
+ *
+ * Return: The maximum, or a negative error code on failure.
  */
 int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, 
 			  struct snd_pcm_hw_params *params,
@@ -1665,6 +1695,8 @@ EXPORT_SYMBOL(snd_pcm_hw_param_last);
  * The configuration chosen is that obtained fixing in this order:
  * first access, first format, first subformat, min channels,
  * min rate, min period time, max buffer size, min tick time
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
 			     struct snd_pcm_hw_params *params)
@@ -1771,7 +1803,7 @@ static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream,
  * Processes the generic ioctl commands for PCM.
  * Can be passed as the ioctl callback for PCM ops.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
 		      unsigned int cmd, void *arg)
@@ -2510,7 +2542,7 @@ static void pcm_chmap_ctl_private_free(struct snd_kcontrol *kcontrol)
  * @info_ret: store struct snd_pcm_chmap instance if non-NULL
  *
  * Create channel-mapping control elements assigned to the given PCM stream(s).
- * Returns zero if succeed, or a negative error value.
+ * Return: Zero if successful, or a negative error value.
  */
 int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream,
 			   const struct snd_pcm_chmap_elem *chmap,
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
index 69e01c4fc32d..0af622c34e19 100644
--- a/sound/core/pcm_memory.c
+++ b/sound/core/pcm_memory.c
@@ -95,7 +95,7 @@ static void snd_pcm_lib_preallocate_dma_free(struct snd_pcm_substream *substream
  *
  * Releases the pre-allocated buffer of the given substream.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream)
 {
@@ -115,7 +115,7 @@ int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream)
  *
  * Releases all the pre-allocated buffers on the given pcm.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm)
 {
@@ -265,7 +265,7 @@ static int snd_pcm_lib_preallocate_pages1(struct snd_pcm_substream *substream,
  * destruction time.  The dma_buf_id must be unique for all systems
  * (in the same DMA buffer type) e.g. using snd_dma_pci_buf_id().
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream,
 				  int type, struct device *data,
@@ -289,7 +289,7 @@ EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages);
  * Do pre-allocation to all substreams of the given pcm for the
  * specified DMA type.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
 					  int type, void *data,
@@ -313,8 +313,9 @@ EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all);
  * @substream: the pcm substream instance
  * @offset: the buffer offset
  *
- * Returns the page struct at the given buffer offset.
  * Used as the page callback of PCM ops.
+ *
+ * Return: The page struct at the given buffer offset. %NULL on failure.
  */
 struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigned long offset)
 {
@@ -337,7 +338,7 @@ EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
  * Allocates the DMA buffer on the BUS type given earlier to
  * snd_pcm_lib_preallocate_xxx_pages().
  *
- * Returns 1 if the buffer is changed, 0 if not changed, or a negative
+ * Return: 1 if the buffer is changed, 0 if not changed, or a negative
  * code on failure.
  */
 int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size)
@@ -390,7 +391,7 @@ EXPORT_SYMBOL(snd_pcm_lib_malloc_pages);
  *
  * Releases the DMA buffer allocated via snd_pcm_lib_malloc_pages().
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream)
 {
@@ -437,6 +438,8 @@ EXPORT_SYMBOL(_snd_pcm_lib_alloc_vmalloc_buffer);
  * snd_pcm_lib_free_vmalloc_buffer - free vmalloc buffer
  * @substream: the substream with a buffer allocated by
  *	snd_pcm_lib_alloc_vmalloc_buffer()
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream)
 {
@@ -458,6 +461,8 @@ EXPORT_SYMBOL(snd_pcm_lib_free_vmalloc_buffer);
  * @offset: offset in the buffer
  *
  * This function is to be used as the page callback in the PCM ops.
+ *
+ * Return: The page struct, or %NULL on failure.
  */
 struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream,
 					  unsigned long offset)
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c
index d4fc1bfbe457..43f24cce3dec 100644
--- a/sound/core/pcm_misc.c
+++ b/sound/core/pcm_misc.c
@@ -140,6 +140,14 @@ static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = {
 		.width = 5, .phys = 5, .le = -1, .signd = -1,
 		.silence = {},
 	},
+	[SNDRV_PCM_FORMAT_DSD_U8] = {
+		.width = 8, .phys = 8, .le = 1, .signd = 0,
+		.silence = {},
+	},
+	[SNDRV_PCM_FORMAT_DSD_U16_LE] = {
+		.width = 16, .phys = 16, .le = 1, .signd = 0,
+		.silence = {},
+	},
 	/* FIXME: the following three formats are not defined properly yet */
 	[SNDRV_PCM_FORMAT_MPEG] = {
 		.le = -1, .signd = -1,
@@ -213,7 +221,7 @@ static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = {
  * snd_pcm_format_signed - Check the PCM format is signed linear
  * @format: the format to check
  *
- * Returns 1 if the given PCM format is signed linear, 0 if unsigned
+ * Return: 1 if the given PCM format is signed linear, 0 if unsigned
  * linear, and a negative error code for non-linear formats.
  */
 int snd_pcm_format_signed(snd_pcm_format_t format)
@@ -232,7 +240,7 @@ EXPORT_SYMBOL(snd_pcm_format_signed);
  * snd_pcm_format_unsigned - Check the PCM format is unsigned linear
  * @format: the format to check
  *
- * Returns 1 if the given PCM format is unsigned linear, 0 if signed
+ * Return: 1 if the given PCM format is unsigned linear, 0 if signed
  * linear, and a negative error code for non-linear formats.
  */
 int snd_pcm_format_unsigned(snd_pcm_format_t format)
@@ -251,7 +259,7 @@ EXPORT_SYMBOL(snd_pcm_format_unsigned);
  * snd_pcm_format_linear - Check the PCM format is linear
  * @format: the format to check
  *
- * Returns 1 if the given PCM format is linear, 0 if not.
+ * Return: 1 if the given PCM format is linear, 0 if not.
  */
 int snd_pcm_format_linear(snd_pcm_format_t format)
 {
@@ -264,7 +272,7 @@ EXPORT_SYMBOL(snd_pcm_format_linear);
  * snd_pcm_format_little_endian - Check the PCM format is little-endian
  * @format: the format to check
  *
- * Returns 1 if the given PCM format is little-endian, 0 if
+ * Return: 1 if the given PCM format is little-endian, 0 if
  * big-endian, or a negative error code if endian not specified.
  */
 int snd_pcm_format_little_endian(snd_pcm_format_t format)
@@ -283,7 +291,7 @@ EXPORT_SYMBOL(snd_pcm_format_little_endian);
  * snd_pcm_format_big_endian - Check the PCM format is big-endian
  * @format: the format to check
  *
- * Returns 1 if the given PCM format is big-endian, 0 if
+ * Return: 1 if the given PCM format is big-endian, 0 if
  * little-endian, or a negative error code if endian not specified.
  */
 int snd_pcm_format_big_endian(snd_pcm_format_t format)
@@ -302,7 +310,7 @@ EXPORT_SYMBOL(snd_pcm_format_big_endian);
  * snd_pcm_format_width - return the bit-width of the format
  * @format: the format to check
  *
- * Returns the bit-width of the format, or a negative error code
+ * Return: The bit-width of the format, or a negative error code
  * if unknown format.
  */
 int snd_pcm_format_width(snd_pcm_format_t format)
@@ -321,7 +329,7 @@ EXPORT_SYMBOL(snd_pcm_format_width);
  * snd_pcm_format_physical_width - return the physical bit-width of the format
  * @format: the format to check
  *
- * Returns the physical bit-width of the format, or a negative error code
+ * Return: The physical bit-width of the format, or a negative error code
  * if unknown format.
  */
 int snd_pcm_format_physical_width(snd_pcm_format_t format)
@@ -341,7 +349,7 @@ EXPORT_SYMBOL(snd_pcm_format_physical_width);
  * @format: the format to check
  * @samples: sampling rate
  *
- * Returns the byte size of the given samples for the format, or a
+ * Return: The byte size of the given samples for the format, or a
  * negative error code if unknown format.
  */
 ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
@@ -358,7 +366,7 @@ EXPORT_SYMBOL(snd_pcm_format_size);
  * snd_pcm_format_silence_64 - return the silent data in 8 bytes array
  * @format: the format to check
  *
- * Returns the format pattern to fill or NULL if error.
+ * Return: The format pattern to fill or %NULL if error.
  */
 const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format)
 {
@@ -379,7 +387,7 @@ EXPORT_SYMBOL(snd_pcm_format_silence_64);
  *
  * Sets the silence data on the buffer for the given samples.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples)
 {
@@ -449,7 +457,7 @@ EXPORT_SYMBOL(snd_pcm_format_set_silence);
  * Determines the rate_min and rate_max fields from the rates bits of
  * the given runtime->hw.
  *
- * Returns zero if successful.
+ * Return: Zero if successful.
  */
 int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime)
 {
@@ -475,7 +483,7 @@ EXPORT_SYMBOL(snd_pcm_limit_hw_rates);
  * snd_pcm_rate_to_rate_bit - converts sample rate to SNDRV_PCM_RATE_xxx bit
  * @rate: the sample rate to convert
  *
- * Returns the SNDRV_PCM_RATE_xxx flag that corresponds to the given rate, or
+ * Return: The SNDRV_PCM_RATE_xxx flag that corresponds to the given rate, or
  * SNDRV_PCM_RATE_KNOT for an unknown rate.
  */
 unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate)
@@ -493,8 +501,8 @@ EXPORT_SYMBOL(snd_pcm_rate_to_rate_bit);
  * snd_pcm_rate_bit_to_rate - converts SNDRV_PCM_RATE_xxx bit to sample rate
  * @rate_bit: the rate bit to convert
  *
- * Returns the sample rate that corresponds to the given SNDRV_PCM_RATE_xxx flag
- * or 0 for an unknown rate bit
+ * Return: The sample rate that corresponds to the given SNDRV_PCM_RATE_xxx flag
+ * or 0 for an unknown rate bit.
  */
 unsigned int snd_pcm_rate_bit_to_rate(unsigned int rate_bit)
 {
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index eb560fa32321..23e3c46cd0a4 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -898,6 +898,8 @@ static struct action_ops snd_pcm_action_start = {
 /**
  * snd_pcm_start - start all linked streams
  * @substream: the PCM substream instance
+ *
+ * Return: Zero if successful, or a negative error code.
  */
 int snd_pcm_start(struct snd_pcm_substream *substream)
 {
@@ -951,6 +953,8 @@ static struct action_ops snd_pcm_action_stop = {
  * @state: PCM state after stopping the stream
  *
  * The state of each stream is then changed to the given state unconditionally.
+ *
+ * Return: Zero if succesful, or a negative error code.
  */
 int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state)
 {
@@ -965,6 +969,8 @@ EXPORT_SYMBOL(snd_pcm_stop);
  *
  * After stopping, the state is changed to SETUP.
  * Unlike snd_pcm_stop(), this affects only the given stream.
+ *
+ * Return: Zero if succesful, or a negative error code.
  */
 int snd_pcm_drain_done(struct snd_pcm_substream *substream)
 {
@@ -1098,6 +1104,9 @@ static struct action_ops snd_pcm_action_suspend = {
  * @substream: the PCM substream
  *
  * After this call, all streams are changed to SUSPENDED state.
+ *
+ * Return: Zero if successful (or @substream is %NULL), or a negative error
+ * code.
  */
 int snd_pcm_suspend(struct snd_pcm_substream *substream)
 {
@@ -1120,6 +1129,8 @@ EXPORT_SYMBOL(snd_pcm_suspend);
  * @pcm: the PCM instance
  *
  * After this call, all streams are changed to SUSPENDED state.
+ *
+ * Return: Zero if successful (or @pcm is %NULL), or a negative error code.
  */
 int snd_pcm_suspend_all(struct snd_pcm *pcm)
 {
@@ -1343,6 +1354,8 @@ static struct action_ops snd_pcm_action_prepare = {
  * snd_pcm_prepare - prepare the PCM substream to be triggerable
  * @substream: the PCM substream instance
  * @file: file to refer f_flags
+ *
+ * Return: Zero if successful, or a negative error code.
  */
 static int snd_pcm_prepare(struct snd_pcm_substream *substream,
 			   struct file *file)
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 1bb95aeea084..7b596b5751db 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -863,7 +863,7 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card,
  *
  * Reads the data from the internal buffer.
  *
- * Returns the size of read data, or a negative error code on failure.
+ * Return: The size of read data, or a negative error code on failure.
  */
 int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
 			const unsigned char *buffer, int count)
@@ -1024,8 +1024,8 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun
 /**
  * snd_rawmidi_transmit_empty - check whether the output buffer is empty
  * @substream: the rawmidi substream
- * 
- * Returns 1 if the internal output buffer is empty, 0 if not.
+ *
+ * Return: 1 if the internal output buffer is empty, 0 if not.
  */
 int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream)
 {
@@ -1055,7 +1055,7 @@ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream)
  * and call snd_rawmidi_transmit_ack() after the transmission is
  * finished.
  *
- * Returns the size of copied data, or a negative error code on failure.
+ * Return: The size of copied data, or a negative error code on failure.
  */
 int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
 			      unsigned char *buffer, int count)
@@ -1107,7 +1107,7 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
  * the given size and updates the condition.
  * Call after the transmission is finished.
  *
- * Returns the advanced size if successful, or a negative error code on failure.
+ * Return: The advanced size if successful, or a negative error code on failure.
  */
 int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
 {
@@ -1140,7 +1140,7 @@ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
  * 
  * Copies data from the buffer to the device and advances the pointer.
  *
- * Returns the copied size if successful, or a negative error code on failure.
+ * Return: The copied size if successful, or a negative error code on failure.
  */
 int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
 			 unsigned char *buffer, int count)
@@ -1438,7 +1438,7 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi,
  * Creates a new rawmidi instance.
  * Use snd_rawmidi_set_ops() to set the operators to the new instance.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_rawmidi_new(struct snd_card *card, char *id, int device,
 		    int output_count, int input_count,
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 70ccdab74153..f002bd911dae 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -102,6 +102,9 @@ static void snd_request_other(int minor)
  * This function increments the reference counter of the card instance
  * if an associated instance with the given minor number and type is found.
  * The caller must call snd_card_unref() appropriately later.
+ *
+ * Return: The user data pointer if the specified device is found. %NULL
+ * otherwise.
  */
 void *snd_lookup_minor_data(unsigned int minor, int type)
 {
@@ -261,7 +264,7 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev)
  * Registers an ALSA device file for the given card.
  * The operators have to be set in reg parameter.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
 				const struct file_operations *f_ops,
@@ -339,7 +342,7 @@ static int find_snd_minor(int type, struct snd_card *card, int dev)
  * Unregisters the device file already registered via
  * snd_register_device().
  *
- * Returns zero if sucecessful, or a negative error code on failure
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_unregister_device(int type, struct snd_card *card, int dev)
 {
diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c
index 0097f3619faa..02f90b4f8b86 100644
--- a/sound/core/vmaster.c
+++ b/sound/core/vmaster.c
@@ -365,8 +365,7 @@ static void master_free(struct snd_kcontrol *kcontrol)
  * @name: name string of the control element to create
  * @tlv: optional TLV int array for dB information
  *
- * Creates a virtual matster control with the given name string.
- * Returns the created control element, or NULL for errors (ENOMEM).
+ * Creates a virtual master control with the given name string.
  *
  * After creating a vmaster element, you can add the slave controls
  * via snd_ctl_add_slave() or snd_ctl_add_slave_uncached().
@@ -375,6 +374,8 @@ static void master_free(struct snd_kcontrol *kcontrol)
  * for dB scale of the master control.  It should be a single element
  * with #SNDRV_CTL_TLVT_DB_SCALE, #SNDRV_CTL_TLV_DB_MINMAX or
  * #SNDRV_CTL_TLVT_DB_MINMAX_MUTE type, and should be the max 0dB.
+ *
+ * Return: The created control element, or %NULL for errors (ENOMEM).
  */
 struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
 						 const unsigned int *tlv)
@@ -426,6 +427,8 @@ EXPORT_SYMBOL(snd_ctl_make_virtual_master);
  *
  * Adds the given hook to the vmaster control element so that it's called
  * at each time when the value is changed.
+ *
+ * Return: Zero.
  */
 int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kcontrol,
 			     void (*hook)(void *private_data, int),
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig
index 7d02c322ed93..8545da99b183 100644
--- a/sound/drivers/Kconfig
+++ b/sound/drivers/Kconfig
@@ -87,7 +87,7 @@ config SND_ALOOP
 	  configured number of substreams (see the pcm_substreams module
           parameter).
 
-	  The looback device allow time sychronization with an external
+	  The loopback device allows time sychronization with an external
 	  timing source using the time shift universal control (+-20%
 	  of system time).
 
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index 64d534710b51..6f78de9c6fb6 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -325,7 +325,7 @@ static void params_change(struct snd_pcm_substream *substream)
 	struct loopback_pcm *dpcm = runtime->private_data;
 	struct loopback_cable *cable = dpcm->cable;
 
-	cable->hw.formats = (1ULL << runtime->format);
+	cable->hw.formats = pcm_format_to_bits(runtime->format);
 	cable->hw.rate_min = runtime->rate;
 	cable->hw.rate_max = runtime->rate;
 	cable->hw.channels_min = runtime->channels;
diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c
index 4608c2ca43f8..e3a90d043f03 100644
--- a/sound/drivers/mpu401/mpu401_uart.c
+++ b/sound/drivers/mpu401/mpu401_uart.c
@@ -129,6 +129,8 @@ static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu)
  * @dev_id: mpu401 instance
  *
  * Processes the interrupt for MPU401-UART i/o.
+ *
+ * Return: %IRQ_HANDLED if the interrupt was handled. %IRQ_NONE otherwise.
  */
 irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id)
 {
@@ -148,6 +150,8 @@ EXPORT_SYMBOL(snd_mpu401_uart_interrupt);
  * @dev_id: mpu401 instance
  *
  * Processes the interrupt for MPU401-UART output.
+ *
+ * Return: %IRQ_HANDLED if the interrupt was handled. %IRQ_NONE otherwise.
  */
 irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id)
 {
@@ -519,7 +523,7 @@ static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi)
  * not the mpu401 instance itself.  To access to the mpu401 instance,
  * cast from rawmidi->private_data (with struct snd_mpu401 magic-cast).
  *
- * Returns zero if successful, or a negative error code.
+ * Return: Zero if successful, or a negative error code.
  */
 int snd_mpu401_uart_new(struct snd_card *card, int device,
 			unsigned short hardware,
diff --git a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c
index bcc3e8e07122..a59c88818f48 100644
--- a/sound/oss/dmabuf.c
+++ b/sound/oss/dmabuf.c
@@ -114,7 +114,7 @@ static int sound_alloc_dmap(struct dma_buffparms *dmap)
 		}
 	}
 	dmap->raw_buf = start_addr;
-	dmap->raw_buf_phys = virt_to_bus(start_addr);
+	dmap->raw_buf_phys = dma_map_single(NULL, start_addr, dmap->buffsize, DMA_BIDIRECTIONAL);
 
 	for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++)
 		SetPageReserved(page);
@@ -139,6 +139,7 @@ static void sound_free_dmap(struct dma_buffparms *dmap)
 	for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++)
 		ClearPageReserved(page);
 
+	dma_unmap_single(NULL, dmap->raw_buf_phys, dmap->buffsize, DMA_BIDIRECTIONAL);
 	free_pages((unsigned long) dmap->raw_buf, sz);
 	dmap->raw_buf = NULL;
 }
diff --git a/sound/oss/sb_common.c b/sound/oss/sb_common.c
index 7d42c5418d1b..851a1da46be1 100644
--- a/sound/oss/sb_common.c
+++ b/sound/oss/sb_common.c
@@ -626,13 +626,12 @@ int sb_dsp_detect(struct address_info *hw_config, int pci, int pciio, struct sb_
 	 */
 
 
-	detected_devc = kmalloc(sizeof(sb_devc), GFP_KERNEL);
+	detected_devc = kmemdup(devc, sizeof(sb_devc), GFP_KERNEL);
 	if (detected_devc == NULL)
 	{
 		printk(KERN_ERR "sb: Can't allocate memory for device information\n");
 		return 0;
 	}
-	memcpy(detected_devc, devc, sizeof(sb_devc));
 	MDB(printk(KERN_INFO "SB %d.%02d detected OK (%x)\n", devc->major, devc->minor, hw_config->io_base));
 	return 1;
 }
diff --git a/sound/oss/uart401.c b/sound/oss/uart401.c
index 8e514a676a0d..5433c6f5eca2 100644
--- a/sound/oss/uart401.c
+++ b/sound/oss/uart401.c
@@ -352,23 +352,26 @@ int probe_uart401(struct address_info *hw_config, struct module *owner)
 		goto cleanup_irq;
 	}
 	conf_printf(name, hw_config);
-	midi_devs[devc->my_dev] = kmalloc(sizeof(struct midi_operations), GFP_KERNEL);
+	midi_devs[devc->my_dev] = kmemdup(&uart401_operations,
+					  sizeof(struct midi_operations),
+					  GFP_KERNEL);
 	if (!midi_devs[devc->my_dev]) {
 		printk(KERN_ERR "uart401: Failed to allocate memory\n");
 		goto cleanup_unload_mididev;
 	}
-	memcpy(midi_devs[devc->my_dev], &uart401_operations, sizeof(struct midi_operations));
 
 	if (owner)
 		midi_devs[devc->my_dev]->owner = owner;
 	
 	midi_devs[devc->my_dev]->devc = devc;
-	midi_devs[devc->my_dev]->converter = kmalloc(sizeof(struct synth_operations), GFP_KERNEL);
+	midi_devs[devc->my_dev]->converter = kmemdup(&std_midi_synth,
+						     sizeof(struct synth_operations),
+						     GFP_KERNEL);
+
 	if (!midi_devs[devc->my_dev]->converter) {
 		printk(KERN_WARNING "uart401: Failed to allocate memory\n");
 		goto cleanup_midi_devs;
 	}
-	memcpy(midi_devs[devc->my_dev]->converter, &std_midi_synth, sizeof(struct synth_operations));
 	strcpy(midi_devs[devc->my_dev]->info.name, name);
 	midi_devs[devc->my_dev]->converter->id = "UART401";
 	midi_devs[devc->my_dev]->converter->midi_dev = devc->my_dev;
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index 8b0f99688303..d37c683cfd7a 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -299,7 +299,7 @@ EXPORT_SYMBOL(snd_ac97_write);
  * Reads a value from the given register.  This will invoke the read
  * callback directly after the register check.
  *
- * Returns the read value.
+ * Return: The read value.
  */
 unsigned short snd_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
 {
@@ -352,7 +352,7 @@ EXPORT_SYMBOL(snd_ac97_write_cache);
  * Compares the value with the register cache and updates the value
  * only when the value is changed.
  *
- * Returns 1 if the value is changed, 0 if no change, or a negative
+ * Return: 1 if the value is changed, 0 if no change, or a negative
  * code on failure.
  */
 int snd_ac97_update(struct snd_ac97 *ac97, unsigned short reg, unsigned short value)
@@ -384,7 +384,7 @@ EXPORT_SYMBOL(snd_ac97_update);
  * Updates the masked-bits on the given register only when the value
  * is changed.
  *
- * Returns 1 if the bits are changed, 0 if no change, or a negative
+ * Return: 1 if the bits are changed, 0 if no change, or a negative
  * code on failure.
  */
 int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value)
@@ -1836,7 +1836,7 @@ void snd_ac97_get_name(struct snd_ac97 *ac97, unsigned int id, char *name, int m
  * snd_ac97_get_short_name - retrieve codec name
  * @ac97: the codec instance
  *
- * Returns the short identifying name of the codec.
+ * Return: The short identifying name of the codec.
  */
 const char *snd_ac97_get_short_name(struct snd_ac97 *ac97)
 {
@@ -1910,7 +1910,7 @@ static int ac97_reset_wait(struct snd_ac97 *ac97, int timeout, int with_modem)
  * The AC97 bus instance is registered as a low-level device, so you don't
  * have to release it manually.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_ac97_bus(struct snd_card *card, int num, struct snd_ac97_bus_ops *ops,
 		 void *private_data, struct snd_ac97_bus **rbus)
@@ -2006,7 +2006,7 @@ static void do_update_power(struct work_struct *work)
  * The ac97 instance is registered as a low-level device, so you don't
  * have to release it manually.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, struct snd_ac97 **rac97)
 {
@@ -2373,6 +2373,8 @@ static struct ac97_power_reg power_regs[PWIDX_SIZE] = {
  * @powerup: non-zero when power up the part
  *
  * Update the AC97 powerdown register bits of the given part.
+ *
+ * Return: Zero.
  */
 int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup)
 {
@@ -2885,7 +2887,7 @@ static int apply_quirk_str(struct snd_ac97 *ac97, const char *typestr)
  * headphone (true line-out) control as "Master".
  * The quirk-list must be terminated with a zero-filled entry.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 
 int snd_ac97_tune_hardware(struct snd_ac97 *ac97, struct ac97_quirk *quirk, const char *override)
diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c
index f1488fc176d5..eab0fc9ff2e0 100644
--- a/sound/pci/ac97/ac97_pcm.c
+++ b/sound/pci/ac97/ac97_pcm.c
@@ -253,7 +253,7 @@ static int set_spdif_rate(struct snd_ac97 *ac97, unsigned short rate)
  * AC97_SPDIF is accepted as a pseudo register to modify the SPDIF
  * status bits.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_ac97_set_rate(struct snd_ac97 *ac97, int reg, unsigned int rate)
 {
@@ -440,6 +440,8 @@ static unsigned int get_rates(struct ac97_pcm *pcm, unsigned int cidx, unsigned
  * It assigns available AC97 slots for given PCMs. If none or only
  * some slots are available, pcm->xxx.slots and pcm->xxx.rslots[] members
  * are reduced and might be zero.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_ac97_pcm_assign(struct snd_ac97_bus *bus,
 			unsigned short pcms_count,
@@ -562,6 +564,8 @@ EXPORT_SYMBOL(snd_ac97_pcm_assign);
  * @slots: a subset of allocated slots (snd_ac97_pcm_assign) for this pcm
  *
  * It locks the specified slots and sets the given rate to AC97 registers.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate,
 		      enum ac97_pcm_cfg cfg, unsigned short slots)
@@ -644,6 +648,8 @@ EXPORT_SYMBOL(snd_ac97_pcm_open);
  * @pcm: the ac97 pcm instance
  *
  * It frees the locked AC97 slots.
+ *
+ * Return: Zero.
  */
 int snd_ac97_pcm_close(struct ac97_pcm *pcm)
 {
@@ -718,6 +724,8 @@ static int double_rate_hw_constraint_channels(struct snd_pcm_hw_params *params,
  *
  * Installs the hardware constraint rules to prevent using double rates and
  * more than two channels at the same time.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_ac97_pcm_double_rate_rules(struct snd_pcm_runtime *runtime)
 {
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index e760af9d1fb6..53754f5edeb1 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -451,10 +451,10 @@ static int snd_ali_reset_5451(struct snd_ali *codec)
 	if (pci_dev) {
 		pci_read_config_dword(pci_dev, 0x7c, &dwVal);
 		pci_write_config_dword(pci_dev, 0x7c, dwVal | 0x08000000);
-		udelay(5000);
+		mdelay(5);
 		pci_read_config_dword(pci_dev, 0x7c, &dwVal);
 		pci_write_config_dword(pci_dev, 0x7c, dwVal & 0xf7ffffff);
-		udelay(5000);
+		mdelay(5);
 	}
 	
 	pci_dev = codec->pci;
@@ -463,14 +463,14 @@ static int snd_ali_reset_5451(struct snd_ali *codec)
 	udelay(500);
 	pci_read_config_dword(pci_dev, 0x44, &dwVal);
 	pci_write_config_dword(pci_dev, 0x44, dwVal & 0xfffbffff);
-	udelay(5000);
+	mdelay(5);
 	
 	wCount = 200;
 	while(wCount--) {
 		wReg = snd_ali_codec_peek(codec, 0, AC97_POWERDOWN);
 		if ((wReg & 0x000f) == 0x000f)
 			return 0;
-		udelay(5000);
+		mdelay(5);
 	}
 
 	/* non-fatal if you have a non PM capable codec */
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index 0aabfedeecba..fbc17203613c 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -966,7 +966,7 @@ static u64 snd_card_asihpi_playback_formats(struct snd_card_asihpi *asihpi,
 		if (!err)
 			err = hpi_outstream_query_format(h_stream, &hpi_format);
 		if (!err && (hpi_to_alsa_formats[format] != -1))
-			formats |= (1ULL << hpi_to_alsa_formats[format]);
+			formats |= pcm_format_to_bits(hpi_to_alsa_formats[format]);
 	}
 	return formats;
 }
@@ -1141,8 +1141,8 @@ static u64 snd_card_asihpi_capture_formats(struct snd_card_asihpi *asihpi,
 					format, sample_rate, 128000, 0);
 		if (!err)
 			err = hpi_instream_query_format(h_stream, &hpi_format);
-		if (!err)
-			formats |= (1ULL << hpi_to_alsa_formats[format]);
+		if (!err && (hpi_to_alsa_formats[format] != -1))
+			formats |= pcm_format_to_bits(hpi_to_alsa_formats[format]);
 	}
 	return formats;
 }
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index e6b016693240..bdd888ec9a84 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -657,14 +657,14 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 *emu)
 	return 0;
 }
 
-static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu)
+static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu,
+				     const struct firmware *fw_entry)
 {
 	int n, i;
 	int reg;
 	int value;
 	unsigned int write_post;
 	unsigned long flags;
-	const struct firmware *fw_entry = emu->firmware;
 
 	if (!fw_entry)
 		return -EIO;
@@ -725,9 +725,34 @@ static int emu1010_firmware_thread(void *data)
 			/* Return to Audio Dock programming mode */
 			snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n");
 			snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK);
-			err = snd_emu1010_load_firmware(emu);
-			if (err != 0)
-				continue;
+
+			if (!emu->dock_fw) {
+				const char *filename = NULL;
+				switch (emu->card_capabilities->emu_model) {
+				case EMU_MODEL_EMU1010:
+					filename = DOCK_FILENAME;
+					break;
+				case EMU_MODEL_EMU1010B:
+					filename = MICRO_DOCK_FILENAME;
+					break;
+				case EMU_MODEL_EMU1616:
+					filename = MICRO_DOCK_FILENAME;
+					break;
+				}
+				if (filename) {
+					err = request_firmware(&emu->dock_fw,
+							       filename,
+							       &emu->pci->dev);
+					if (err)
+						continue;
+				}
+			}
+
+			if (emu->dock_fw) {
+				err = snd_emu1010_load_firmware(emu, emu->dock_fw);
+				if (err)
+					continue;
+			}
 
 			snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0);
 			snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &reg);
@@ -862,7 +887,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
 			   filename, emu->firmware->size);
 	}
 
-	err = snd_emu1010_load_firmware(emu);
+	err = snd_emu1010_load_firmware(emu, emu->firmware);
 	if (err != 0) {
 		snd_printk(KERN_INFO "emu1010: Loading Firmware failed\n");
 		return err;
@@ -1253,6 +1278,8 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)
 		kthread_stop(emu->emu1010.firmware_thread);
 	if (emu->firmware)
 		release_firmware(emu->firmware);
+	if (emu->dock_fw)
+		release_firmware(emu->dock_fw);
 	if (emu->irq >= 0)
 		free_irq(emu->irq, emu);
 	/* remove reserved page */
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
index a3ea76a4c9d2..7c11d46b84d3 100644
--- a/sound/pci/hda/hda_auto_parser.c
+++ b/sound/pci/hda/hda_auto_parser.c
@@ -119,6 +119,32 @@ static bool check_pincap_validity(struct hda_codec *codec, hda_nid_t pin,
 	}
 }
 
+static bool can_be_headset_mic(struct hda_codec *codec,
+			       struct auto_pin_cfg_item *item,
+			       int seq_number)
+{
+	int attr;
+	unsigned int def_conf;
+	if (item->type != AUTO_PIN_MIC)
+		return false;
+
+	if (item->is_headset_mic || item->is_headphone_mic)
+		return false; /* Already assigned */
+
+	def_conf = snd_hda_codec_get_pincfg(codec, item->pin);
+	attr = snd_hda_get_input_pin_attr(def_conf);
+	if (attr <= INPUT_PIN_ATTR_DOCK)
+		return false;
+
+	if (seq_number >= 0) {
+		int seq = get_defcfg_sequence(def_conf);
+		if (seq != seq_number)
+			return false;
+	}
+
+	return true;
+}
+
 /*
  * Parse all pin widgets and store the useful pin nids to cfg
  *
@@ -260,6 +286,38 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
 		}
 	}
 
+	/* Find a pin that could be a headset or headphone mic */
+	if (cond_flags & HDA_PINCFG_HEADSET_MIC || cond_flags & HDA_PINCFG_HEADPHONE_MIC) {
+		bool hsmic = !!(cond_flags & HDA_PINCFG_HEADSET_MIC);
+		bool hpmic = !!(cond_flags & HDA_PINCFG_HEADPHONE_MIC);
+		for (i = 0; (hsmic || hpmic) && (i < cfg->num_inputs); i++)
+			if (hsmic && can_be_headset_mic(codec, &cfg->inputs[i], 0xc)) {
+				cfg->inputs[i].is_headset_mic = 1;
+				hsmic = false;
+			} else if (hpmic && can_be_headset_mic(codec, &cfg->inputs[i], 0xd)) {
+				cfg->inputs[i].is_headphone_mic = 1;
+				hpmic = false;
+			}
+
+		/* If we didn't find our sequence number mark, fall back to any sequence number */
+		for (i = 0; (hsmic || hpmic) && (i < cfg->num_inputs); i++) {
+			if (!can_be_headset_mic(codec, &cfg->inputs[i], -1))
+				continue;
+			if (hsmic) {
+				cfg->inputs[i].is_headset_mic = 1;
+				hsmic = false;
+			} else if (hpmic) {
+				cfg->inputs[i].is_headphone_mic = 1;
+				hpmic = false;
+			}
+		}
+
+		if (hsmic)
+			snd_printdd("Told to look for a headset mic, but didn't find any.\n");
+		if (hpmic)
+			snd_printdd("Told to look for a headphone mic, but didn't find any.\n");
+	}
+
 	/* FIX-UP:
 	 * If no line-out is defined but multiple HPs are found,
 	 * some of them might be the real line-outs.
@@ -388,6 +446,7 @@ EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr);
  */
 
 static const char *hda_get_input_pin_label(struct hda_codec *codec,
+					   const struct auto_pin_cfg_item *item,
 					   hda_nid_t pin, bool check_location)
 {
 	unsigned int def_conf;
@@ -400,6 +459,10 @@ static const char *hda_get_input_pin_label(struct hda_codec *codec,
 
 	switch (get_defcfg_device(def_conf)) {
 	case AC_JACK_MIC_IN:
+		if (item && item->is_headset_mic)
+			return "Headset Mic";
+		if (item && item->is_headphone_mic)
+			return "Headphone Mic";
 		if (!check_location)
 			return "Mic";
 		attr = snd_hda_get_input_pin_attr(def_conf);
@@ -480,7 +543,8 @@ const char *hda_get_autocfg_input_label(struct hda_codec *codec,
 		has_multiple_pins = 1;
 	if (has_multiple_pins && type == AUTO_PIN_MIC)
 		has_multiple_pins &= check_mic_location_need(codec, cfg, input);
-	return hda_get_input_pin_label(codec, cfg->inputs[input].pin,
+	return hda_get_input_pin_label(codec, &cfg->inputs[input],
+				       cfg->inputs[input].pin,
 				       has_multiple_pins);
 }
 EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label);
@@ -649,7 +713,7 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
 			}
 		}
 		if (!name)
-			name = hda_get_input_pin_label(codec, nid, true);
+			name = hda_get_input_pin_label(codec, NULL, nid, true);
 		break;
 	}
 	if (!name)
diff --git a/sound/pci/hda/hda_auto_parser.h b/sound/pci/hda/hda_auto_parser.h
index f74807138b49..e941f604f5e5 100644
--- a/sound/pci/hda/hda_auto_parser.h
+++ b/sound/pci/hda/hda_auto_parser.h
@@ -36,6 +36,8 @@ enum {
 struct auto_pin_cfg_item {
 	hda_nid_t pin;
 	int type;
+	unsigned int is_headset_mic:1;
+	unsigned int is_headphone_mic:1; /* Mic-only in headphone jack */
 };
 
 struct auto_pin_cfg;
@@ -78,8 +80,10 @@ struct auto_pin_cfg {
 };
 
 /* bit-flags for snd_hda_parse_pin_def_config() behavior */
-#define HDA_PINCFG_NO_HP_FIXUP	(1 << 0) /* no HP-split */
-#define HDA_PINCFG_NO_LO_FIXUP	(1 << 1) /* don't take other outs as LO */
+#define HDA_PINCFG_NO_HP_FIXUP   (1 << 0) /* no HP-split */
+#define HDA_PINCFG_NO_LO_FIXUP   (1 << 1) /* don't take other outs as LO */
+#define HDA_PINCFG_HEADSET_MIC   (1 << 2) /* Try to find headset mic; mark seq number as 0xc to trigger */
+#define HDA_PINCFG_HEADPHONE_MIC (1 << 3) /* Try to find headphone mic; mark seq number as 0xd to trigger */
 
 int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
 			     struct auto_pin_cfg *cfg,
@@ -90,4 +94,25 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
 #define snd_hda_parse_pin_def_config(codec, cfg, ignore) \
 	snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0)
 
+static inline int auto_cfg_hp_outs(const struct auto_pin_cfg *cfg)
+{
+	return (cfg->line_out_type == AUTO_PIN_HP_OUT) ?
+	       cfg->line_outs : cfg->hp_outs;
+}
+static inline const hda_nid_t *auto_cfg_hp_pins(const struct auto_pin_cfg *cfg)
+{
+	return (cfg->line_out_type == AUTO_PIN_HP_OUT) ?
+	       cfg->line_out_pins : cfg->hp_pins;
+}
+static inline int auto_cfg_speaker_outs(const struct auto_pin_cfg *cfg)
+{
+	return (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) ?
+	       cfg->line_outs : cfg->speaker_outs;
+}
+static inline const hda_nid_t *auto_cfg_speaker_pins(const struct auto_pin_cfg *cfg)
+{
+	return (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) ?
+	       cfg->line_out_pins : cfg->speaker_pins;
+}
+
 #endif /* __SOUND_HDA_AUTO_PARSER_H */
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
index 0849aac449f2..63c99090a4ec 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/pci/hda/hda_beep.c
@@ -39,13 +39,23 @@ static void snd_hda_generate_beep(struct work_struct *work)
 	struct hda_beep *beep =
 		container_of(work, struct hda_beep, beep_work);
 	struct hda_codec *codec = beep->codec;
+	int tone;
 
 	if (!beep->enabled)
 		return;
 
+	tone = beep->tone;
+	if (tone && !beep->playing) {
+		snd_hda_power_up(codec);
+		beep->playing = 1;
+	}
 	/* generate tone */
 	snd_hda_codec_write(codec, beep->nid, 0,
-			AC_VERB_SET_BEEP_CONTROL, beep->tone);
+			    AC_VERB_SET_BEEP_CONTROL, tone);
+	if (!tone && beep->playing) {
+		beep->playing = 0;
+		snd_hda_power_down(codec);
+	}
 }
 
 /* (non-standard) Linear beep tone calculation for IDT/STAC codecs 
@@ -115,14 +125,23 @@ static int snd_hda_beep_event(struct input_dev *dev, unsigned int type,
 	return 0;
 }
 
+static void turn_off_beep(struct hda_beep *beep)
+{
+	cancel_work_sync(&beep->beep_work);
+	if (beep->playing) {
+		/* turn off beep */
+		snd_hda_codec_write(beep->codec, beep->nid, 0,
+				    AC_VERB_SET_BEEP_CONTROL, 0);
+		beep->playing = 0;
+		snd_hda_power_down(beep->codec);
+	}
+}
+
 static void snd_hda_do_detach(struct hda_beep *beep)
 {
 	input_unregister_device(beep->dev);
 	beep->dev = NULL;
-	cancel_work_sync(&beep->beep_work);
-	/* turn off beep for sure */
-	snd_hda_codec_write(beep->codec, beep->nid, 0,
-				  AC_VERB_SET_BEEP_CONTROL, 0);
+	turn_off_beep(beep);
 }
 
 static int snd_hda_do_attach(struct hda_beep *beep)
@@ -170,12 +189,8 @@ int snd_hda_enable_beep_device(struct hda_codec *codec, int enable)
 	enable = !!enable;
 	if (beep->enabled != enable) {
 		beep->enabled = enable;
-		if (!enable) {
-			cancel_work_sync(&beep->beep_work);
-			/* turn off beep */
-			snd_hda_codec_write(beep->codec, beep->nid, 0,
-						  AC_VERB_SET_BEEP_CONTROL, 0);
-		}
+		if (!enable)
+			turn_off_beep(beep);
 		return 1;
 	}
 	return 0;
@@ -198,7 +213,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
 	snprintf(beep->phys, sizeof(beep->phys),
 		"card%d/codec#%d/beep0", codec->bus->card->number, codec->addr);
 	/* enable linear scale */
-	snd_hda_codec_write(codec, nid, 0,
+	snd_hda_codec_write_cache(codec, nid, 0,
 		AC_VERB_SET_DIGI_CONVERT_2, 0x01);
 
 	beep->nid = nid;
diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h
index 4dc6933bc655..cb88464676b6 100644
--- a/sound/pci/hda/hda_beep.h
+++ b/sound/pci/hda/hda_beep.h
@@ -36,6 +36,7 @@ struct hda_beep {
 	hda_nid_t nid;
 	unsigned int enabled:1;
 	unsigned int linear_tone:1;	/* linear tone for IDT/STAC codec */
+	unsigned int playing:1;
 	struct work_struct beep_work; /* scheduled task for beep event */
 	struct mutex mutex;
 };
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 4aba7646dd9c..6f9b64700f6e 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1065,8 +1065,14 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
 {
 	struct hda_pincfg *pin;
 
+	/* the check below may be invalid when pins are added by a fixup
+	 * dynamically (e.g. via snd_hda_codec_update_widgets()), so disabled
+	 * for now
+	 */
+	/*
 	if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
 		return -EINVAL;
+	*/
 
 	pin = look_up_pincfg(codec, list, nid);
 	if (!pin) {
@@ -1300,8 +1306,6 @@ static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec,
 
 static unsigned int hda_set_power_state(struct hda_codec *codec,
 				unsigned int power_state);
-static unsigned int default_power_filter(struct hda_codec *codec, hda_nid_t nid,
-					 unsigned int power_state);
 
 /**
  * snd_hda_codec_new - create a HDA codec
@@ -1422,7 +1426,6 @@ int snd_hda_codec_new(struct hda_bus *bus,
 #endif
 	codec->epss = snd_hda_codec_get_supported_ps(codec, fg,
 					AC_PWRST_EPSS);
-	codec->power_filter = default_power_filter;
 
 	/* power-up all before initialization */
 	hda_set_power_state(codec, AC_PWRST_D0);
@@ -2787,6 +2790,11 @@ void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook)
 {
 	if (!hook->hook || !hook->codec)
 		return;
+	/* don't call vmaster hook in the destructor since it might have
+	 * been already destroyed
+	 */
+	if (hook->codec->bus->shutdown)
+		return;
 	switch (hook->mute_mode) {
 	case HDA_VMUTE_FOLLOW_MASTER:
 		snd_ctl_sync_vmaster_hook(hook->sw_kctl);
@@ -3770,8 +3778,9 @@ static unsigned int hda_sync_power_state(struct hda_codec *codec,
 }
 
 /* don't power down the widget if it controls eapd and EAPD_BTLENABLE is set */
-static unsigned int default_power_filter(struct hda_codec *codec, hda_nid_t nid,
-					 unsigned int power_state)
+unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
+					     hda_nid_t nid,
+					     unsigned int power_state)
 {
 	if (power_state == AC_PWRST_D3 &&
 	    get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_PIN &&
@@ -3783,6 +3792,7 @@ static unsigned int default_power_filter(struct hda_codec *codec, hda_nid_t nid,
 	}
 	return power_state;
 }
+EXPORT_SYMBOL_HDA(snd_hda_codec_eapd_power_filter);
 
 /*
  * set power state of the codec, and return the power state
@@ -3827,8 +3837,8 @@ static void sync_power_up_states(struct hda_codec *codec)
 	hda_nid_t nid = codec->start_nid;
 	int i;
 
-	/* don't care if no or standard filter is used */
-	if (!codec->power_filter || codec->power_filter == default_power_filter)
+	/* don't care if no filter is used */
+	if (!codec->power_filter)
 		return;
 
 	for (i = 0; i < codec->num_nodes; i++, nid++) {
@@ -5546,14 +5556,12 @@ void *snd_array_new(struct snd_array *array)
 	if (array->used >= array->alloced) {
 		int num = array->alloced + array->alloc_align;
 		int size = (num + 1) * array->elem_size;
-		int oldsize = array->alloced * array->elem_size;
 		void *nlist;
 		if (snd_BUG_ON(num >= 4096))
 			return NULL;
-		nlist = krealloc(array->list, size, GFP_KERNEL);
+		nlist = krealloc(array->list, size, GFP_KERNEL | __GFP_ZERO);
 		if (!nlist)
 			return NULL;
-		memset(nlist + oldsize, 0, size - oldsize);
 		array->list = nlist;
 		array->alloced = num;
 	}
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 23ca1722aff1..c93f9021f452 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -757,6 +757,9 @@ struct hda_pcm_ops {
 		       struct snd_pcm_substream *substream);
 	int (*cleanup)(struct hda_pcm_stream *info, struct hda_codec *codec,
 		       struct snd_pcm_substream *substream);
+	unsigned int (*get_delay)(struct hda_pcm_stream *info,
+				  struct hda_codec *codec,
+				  struct snd_pcm_substream *substream);
 };
 
 /* PCM information for each substream */
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 2dbe767be16b..ac079f93c535 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -34,6 +34,7 @@
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_jack.h"
+#include "hda_beep.h"
 #include "hda_generic.h"
 
 
@@ -150,15 +151,25 @@ static void parse_user_hints(struct hda_codec *codec)
 	val = snd_hda_get_bool_hint(codec, "add_stereo_mix_input");
 	if (val >= 0)
 		spec->add_stereo_mix_input = !!val;
+	/* the following two are just for compatibility */
 	val = snd_hda_get_bool_hint(codec, "add_out_jack_modes");
 	if (val >= 0)
-		spec->add_out_jack_modes = !!val;
+		spec->add_jack_modes = !!val;
 	val = snd_hda_get_bool_hint(codec, "add_in_jack_modes");
 	if (val >= 0)
-		spec->add_in_jack_modes = !!val;
+		spec->add_jack_modes = !!val;
+	val = snd_hda_get_bool_hint(codec, "add_jack_modes");
+	if (val >= 0)
+		spec->add_jack_modes = !!val;
 	val = snd_hda_get_bool_hint(codec, "power_down_unused");
 	if (val >= 0)
 		spec->power_down_unused = !!val;
+	val = snd_hda_get_bool_hint(codec, "add_hp_mic");
+	if (val >= 0)
+		spec->hp_mic = !!val;
+	val = snd_hda_get_bool_hint(codec, "hp_mic_detect");
+	if (val >= 0)
+		spec->suppress_hp_mic_detect = !val;
 
 	if (!snd_hda_get_int_hint(codec, "mixer_nid", &val))
 		spec->mixer_nid = val;
@@ -996,7 +1007,7 @@ enum {
 	/* Primary DAC shared with main surrounds */
 	BAD_SHARED_SURROUND = 0x100,
 	/* No independent HP possible */
-	BAD_NO_INDEP_HP = 0x40,
+	BAD_NO_INDEP_HP = 0x10,
 	/* Primary DAC shared with main CLFE */
 	BAD_SHARED_CLFE = 0x10,
 	/* Primary DAC shared with extra surrounds */
@@ -1051,16 +1062,7 @@ static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path)
 	return badness;
 }
 
-struct badness_table {
-	int no_primary_dac;	/* no primary DAC */
-	int no_dac;		/* no secondary DACs */
-	int shared_primary;	/* primary DAC is shared with main output */
-	int shared_surr;	/* secondary DAC shared with main or primary */
-	int shared_clfe;	/* third DAC shared with main or primary */
-	int shared_surr_main;	/* secondary DAC sahred with main/DAC0 */
-};
-
-static struct badness_table main_out_badness = {
+const struct badness_table hda_main_out_badness = {
 	.no_primary_dac = BAD_NO_PRIMARY_DAC,
 	.no_dac = BAD_NO_DAC,
 	.shared_primary = BAD_NO_PRIMARY_DAC,
@@ -1068,8 +1070,9 @@ static struct badness_table main_out_badness = {
 	.shared_clfe = BAD_SHARED_CLFE,
 	.shared_surr_main = BAD_SHARED_SURROUND,
 };
+EXPORT_SYMBOL_HDA(hda_main_out_badness);
 
-static struct badness_table extra_out_badness = {
+const struct badness_table hda_extra_out_badness = {
 	.no_primary_dac = BAD_NO_DAC,
 	.no_dac = BAD_NO_DAC,
 	.shared_primary = BAD_NO_EXTRA_DAC,
@@ -1077,6 +1080,7 @@ static struct badness_table extra_out_badness = {
 	.shared_clfe = BAD_SHARED_EXTRA_SURROUND,
 	.shared_surr_main = BAD_NO_EXTRA_SURR_DAC,
 };
+EXPORT_SYMBOL_HDA(hda_extra_out_badness);
 
 /* get the DAC of the primary output corresponding to the given array index */
 static hda_nid_t get_primary_out(struct hda_codec *codec, int idx)
@@ -1367,22 +1371,25 @@ static int check_aamix_out_path(struct hda_codec *codec, int path_idx)
 {
 	struct hda_gen_spec *spec = codec->spec;
 	struct nid_path *path;
-	hda_nid_t dac, pin;
+	hda_nid_t path_dac, dac, pin;
 
 	path = snd_hda_get_path_from_idx(codec, path_idx);
 	if (!path || !path->depth ||
 	    is_nid_contained(path, spec->mixer_nid))
 		return 0;
-	dac = path->path[0];
+	path_dac = path->path[0];
+	dac = spec->private_dac_nids[0];
 	pin = path->path[path->depth - 1];
 	path = snd_hda_add_new_path(codec, dac, pin, spec->mixer_nid);
 	if (!path) {
-		if (dac != spec->multiout.dac_nids[0])
-			dac = spec->multiout.dac_nids[0];
+		if (dac != path_dac)
+			dac = path_dac;
 		else if (spec->multiout.hp_out_nid[0])
 			dac = spec->multiout.hp_out_nid[0];
 		else if (spec->multiout.extra_out_nid[0])
 			dac = spec->multiout.extra_out_nid[0];
+		else
+			dac = 0;
 		if (dac)
 			path = snd_hda_add_new_path(codec, dac, pin,
 						    spec->mixer_nid);
@@ -1507,7 +1514,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
 
 	badness += try_assign_dacs(codec, cfg->line_outs, cfg->line_out_pins,
 				   spec->private_dac_nids, spec->out_paths,
-				   &main_out_badness);
+				   spec->main_out_badness);
 
 	if (fill_mio_first &&
 	    cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
@@ -1522,7 +1529,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
 		err = try_assign_dacs(codec, cfg->hp_outs, cfg->hp_pins,
 				      spec->multiout.hp_out_nid,
 				      spec->hp_paths,
-				      &extra_out_badness);
+				      spec->extra_out_badness);
 		if (err < 0)
 			return err;
 		badness += err;
@@ -1532,7 +1539,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
 				      cfg->speaker_pins,
 				      spec->multiout.extra_out_nid,
 				      spec->speaker_paths,
-				      &extra_out_badness);
+				      spec->extra_out_badness);
 		if (err < 0)
 			return err;
 		badness += err;
@@ -1926,6 +1933,17 @@ static int create_speaker_out_ctls(struct hda_codec *codec)
  * independent HP controls
  */
 
+/* update HP auto-mute state too */
+static void update_hp_automute_hook(struct hda_codec *codec)
+{
+	struct hda_gen_spec *spec = codec->spec;
+
+	if (spec->hp_automute_hook)
+		spec->hp_automute_hook(codec, NULL);
+	else
+		snd_hda_gen_hp_automute(codec, NULL);
+}
+
 static int indep_hp_info(struct snd_kcontrol *kcontrol,
 			 struct snd_ctl_elem_info *uinfo)
 {
@@ -1986,12 +2004,7 @@ static int indep_hp_put(struct snd_kcontrol *kcontrol,
 		else
 			*dacp = spec->alt_dac_nid;
 
-		/* update HP auto-mute state too */
-		if (spec->hp_automute_hook)
-			spec->hp_automute_hook(codec, NULL);
-		else
-			snd_hda_gen_hp_automute(codec, NULL);
-
+		update_hp_automute_hook(codec);
 		ret = 1;
 	}
  unlock:
@@ -2072,6 +2085,14 @@ get_multiio_path(struct hda_codec *codec, int idx)
 
 static void update_automute_all(struct hda_codec *codec);
 
+/* Default value to be passed as aamix argument for snd_hda_activate_path();
+ * used for output paths
+ */
+static bool aamix_default(struct hda_gen_spec *spec)
+{
+	return !spec->have_aamix_ctl || spec->aamix_mode;
+}
+
 static int set_multi_io(struct hda_codec *codec, int idx, bool output)
 {
 	struct hda_gen_spec *spec = codec->spec;
@@ -2087,11 +2108,11 @@ static int set_multi_io(struct hda_codec *codec, int idx, bool output)
 
 	if (output) {
 		set_pin_target(codec, nid, PIN_OUT, true);
-		snd_hda_activate_path(codec, path, true, true);
+		snd_hda_activate_path(codec, path, true, aamix_default(spec));
 		set_pin_eapd(codec, nid, true);
 	} else {
 		set_pin_eapd(codec, nid, false);
-		snd_hda_activate_path(codec, path, false, true);
+		snd_hda_activate_path(codec, path, false, aamix_default(spec));
 		set_pin_target(codec, nid, spec->multi_io[idx].ctl_in, true);
 		path_power_down_sync(codec, path);
 	}
@@ -2182,8 +2203,8 @@ static void update_aamix_paths(struct hda_codec *codec, bool do_mix,
 		snd_hda_activate_path(codec, mix_path, true, true);
 		path_power_down_sync(codec, nomix_path);
 	} else {
-		snd_hda_activate_path(codec, mix_path, false, true);
-		snd_hda_activate_path(codec, nomix_path, true, true);
+		snd_hda_activate_path(codec, mix_path, false, false);
+		snd_hda_activate_path(codec, nomix_path, true, false);
 		path_power_down_sync(codec, mix_path);
 	}
 }
@@ -2240,63 +2261,95 @@ static int create_loopback_mixing_ctl(struct hda_codec *codec)
 static void call_update_outputs(struct hda_codec *codec);
 
 /* for shared I/O, change the pin-control accordingly */
-static void update_shared_mic_hp(struct hda_codec *codec, bool set_as_mic)
+static void update_hp_mic(struct hda_codec *codec, int adc_mux, bool force)
 {
 	struct hda_gen_spec *spec = codec->spec;
+	bool as_mic;
 	unsigned int val;
-	hda_nid_t pin = spec->autocfg.inputs[1].pin;
-	/* NOTE: this assumes that there are only two inputs, the
-	 * first is the real internal mic and the second is HP/mic jack.
-	 */
+	hda_nid_t pin;
 
-	val = snd_hda_get_default_vref(codec, pin);
+	pin = spec->hp_mic_pin;
+	as_mic = spec->cur_mux[adc_mux] == spec->hp_mic_mux_idx;
+
+	if (!force) {
+		val = snd_hda_codec_get_pin_target(codec, pin);
+		if (as_mic) {
+			if (val & PIN_IN)
+				return;
+		} else {
+			if (val & PIN_OUT)
+				return;
+		}
+	}
 
-	/* This pin does not have vref caps - let's enable vref on pin 0x18
-	   instead, as suggested by Realtek */
+	val = snd_hda_get_default_vref(codec, pin);
+	/* if the HP pin doesn't support VREF and the codec driver gives an
+	 * alternative pin, set up the VREF on that pin instead
+	 */
 	if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) {
 		const hda_nid_t vref_pin = spec->shared_mic_vref_pin;
 		unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin);
 		if (vref_val != AC_PINCTL_VREF_HIZ)
 			snd_hda_set_pin_ctl_cache(codec, vref_pin,
-					PIN_IN | (set_as_mic ? vref_val : 0));
+						  PIN_IN | (as_mic ? vref_val : 0));
 	}
 
-	val = set_as_mic ? val | PIN_IN : PIN_HP;
-	set_pin_target(codec, pin, val, true);
-
-	spec->automute_speaker = !set_as_mic;
-	call_update_outputs(codec);
+	if (!spec->hp_mic_jack_modes) {
+		if (as_mic)
+			val |= PIN_IN;
+		else
+			val = PIN_HP;
+		set_pin_target(codec, pin, val, true);
+		update_hp_automute_hook(codec);
+	}
 }
 
 /* create a shared input with the headphone out */
-static int create_shared_input(struct hda_codec *codec)
+static int create_hp_mic(struct hda_codec *codec)
 {
 	struct hda_gen_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
 	unsigned int defcfg;
 	hda_nid_t nid;
 
-	/* only one internal input pin? */
-	if (cfg->num_inputs != 1)
-		return 0;
-	defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin);
-	if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT)
+	if (!spec->hp_mic) {
+		if (spec->suppress_hp_mic_detect)
+			return 0;
+		/* automatic detection: only if no input or a single internal
+		 * input pin is found, try to detect the shared hp/mic
+		 */
+		if (cfg->num_inputs > 1)
+			return 0;
+		else if (cfg->num_inputs == 1) {
+			defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin);
+			if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT)
+				return 0;
+		}
+	}
+
+	spec->hp_mic = 0; /* clear once */
+	if (cfg->num_inputs >= AUTO_CFG_MAX_INS)
 		return 0;
 
-	if (cfg->hp_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
-		nid = cfg->hp_pins[0]; /* OK, we have a single HP-out */
-	else if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_HP_OUT)
-		nid = cfg->line_out_pins[0]; /* OK, we have a single line-out */
-	else
-		return 0; /* both not available */
+	nid = 0;
+	if (cfg->line_out_type == AUTO_PIN_HP_OUT && cfg->line_outs > 0)
+		nid = cfg->line_out_pins[0];
+	else if (cfg->hp_outs > 0)
+		nid = cfg->hp_pins[0];
+	if (!nid)
+		return 0;
 
 	if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN))
 		return 0; /* no input */
 
-	cfg->inputs[1].pin = nid;
-	cfg->inputs[1].type = AUTO_PIN_MIC;
-	cfg->num_inputs = 2;
-	spec->shared_mic_hp = 1;
+	cfg->inputs[cfg->num_inputs].pin = nid;
+	cfg->inputs[cfg->num_inputs].type = AUTO_PIN_MIC;
+	cfg->inputs[cfg->num_inputs].is_headphone_mic = 1;
+	cfg->num_inputs++;
+	spec->hp_mic = 1;
+	spec->hp_mic_pin = nid;
+	/* we can't handle auto-mic together with HP-mic */
+	spec->suppress_auto_mic = 1;
 	snd_printdd("hda-codec: Enable shared I/O jack on NID 0x%x\n", nid);
 	return 0;
 }
@@ -2304,13 +2357,17 @@ static int create_shared_input(struct hda_codec *codec)
 /*
  * output jack mode
  */
+
+static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin);
+
+static const char * const out_jack_texts[] = {
+	"Line Out", "Headphone Out",
+};
+
 static int out_jack_mode_info(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_info *uinfo)
 {
-	static const char * const texts[] = {
-		"Line Out", "Headphone Out",
-	};
-	return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts);
+	return snd_hda_enum_helper_info(kcontrol, uinfo, 2, out_jack_texts);
 }
 
 static int out_jack_mode_get(struct snd_kcontrol *kcontrol,
@@ -2372,6 +2429,17 @@ static void get_jack_mode_name(struct hda_codec *codec, hda_nid_t pin,
 		;
 }
 
+static int get_out_jack_num_items(struct hda_codec *codec, hda_nid_t pin)
+{
+	struct hda_gen_spec *spec = codec->spec;
+	if (spec->add_jack_modes) {
+		unsigned int pincap = snd_hda_query_pin_caps(codec, pin);
+		if ((pincap & AC_PINCAP_OUT) && (pincap & AC_PINCAP_HP_DRV))
+			return 2;
+	}
+	return 1;
+}
+
 static int create_out_jack_modes(struct hda_codec *codec, int num_pins,
 				 hda_nid_t *pins)
 {
@@ -2380,8 +2448,13 @@ static int create_out_jack_modes(struct hda_codec *codec, int num_pins,
 
 	for (i = 0; i < num_pins; i++) {
 		hda_nid_t pin = pins[i];
-		unsigned int pincap = snd_hda_query_pin_caps(codec, pin);
-		if ((pincap & AC_PINCAP_OUT) && (pincap & AC_PINCAP_HP_DRV)) {
+		if (pin == spec->hp_mic_pin) {
+			int ret = create_hp_mic_jack_mode(codec, pin);
+			if (ret < 0)
+				return ret;
+			continue;
+		}
+		if (get_out_jack_num_items(codec, pin) > 1) {
 			struct snd_kcontrol_new *knew;
 			char name[44];
 			get_jack_mode_name(codec, pin, name, sizeof(name));
@@ -2502,12 +2575,24 @@ static const struct snd_kcontrol_new in_jack_mode_enum = {
 	.put = in_jack_mode_put,
 };
 
+static int get_in_jack_num_items(struct hda_codec *codec, hda_nid_t pin)
+{
+	struct hda_gen_spec *spec = codec->spec;
+	int nitems = 0;
+	if (spec->add_jack_modes)
+		nitems = hweight32(get_vref_caps(codec, pin));
+	return nitems ? nitems : 1;
+}
+
 static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin)
 {
 	struct hda_gen_spec *spec = codec->spec;
-	unsigned int defcfg;
 	struct snd_kcontrol_new *knew;
 	char name[44];
+	unsigned int defcfg;
+
+	if (pin == spec->hp_mic_pin)
+		return 0; /* already done in create_out_jack_mode() */
 
 	/* no jack mode for fixed pins */
 	defcfg = snd_hda_codec_get_pincfg(codec, pin);
@@ -2515,7 +2600,7 @@ static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin)
 		return 0;
 
 	/* no multiple vref caps? */
-	if (hweight32(get_vref_caps(codec, pin)) <= 1)
+	if (get_in_jack_num_items(codec, pin) <= 1)
 		return 0;
 
 	get_jack_mode_name(codec, pin, name, sizeof(name));
@@ -2526,6 +2611,132 @@ static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin)
 	return 0;
 }
 
+/*
+ * HP/mic shared jack mode
+ */
+static int hp_mic_jack_mode_info(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = kcontrol->private_value;
+	int out_jacks = get_out_jack_num_items(codec, nid);
+	int in_jacks = get_in_jack_num_items(codec, nid);
+	const char *text = NULL;
+	int idx;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = out_jacks + in_jacks;
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+	idx = uinfo->value.enumerated.item;
+	if (idx < out_jacks) {
+		if (out_jacks > 1)
+			text = out_jack_texts[idx];
+		else
+			text = "Headphone Out";
+	} else {
+		idx -= out_jacks;
+		if (in_jacks > 1) {
+			unsigned int vref_caps = get_vref_caps(codec, nid);
+			text = vref_texts[get_vref_idx(vref_caps, idx)];
+		} else
+			text = "Mic In";
+	}
+
+	strcpy(uinfo->value.enumerated.name, text);
+	return 0;
+}
+
+static int get_cur_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t nid)
+{
+	int out_jacks = get_out_jack_num_items(codec, nid);
+	int in_jacks = get_in_jack_num_items(codec, nid);
+	unsigned int val = snd_hda_codec_get_pin_target(codec, nid);
+	int idx = 0;
+
+	if (val & PIN_OUT) {
+		if (out_jacks > 1 && val == PIN_HP)
+			idx = 1;
+	} else if (val & PIN_IN) {
+		idx = out_jacks;
+		if (in_jacks > 1) {
+			unsigned int vref_caps = get_vref_caps(codec, nid);
+			val &= AC_PINCTL_VREFEN;
+			idx += cvt_from_vref_idx(vref_caps, val);
+		}
+	}
+	return idx;
+}
+
+static int hp_mic_jack_mode_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = kcontrol->private_value;
+	ucontrol->value.enumerated.item[0] =
+		get_cur_hp_mic_jack_mode(codec, nid);
+	return 0;
+}
+
+static int hp_mic_jack_mode_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = kcontrol->private_value;
+	int out_jacks = get_out_jack_num_items(codec, nid);
+	int in_jacks = get_in_jack_num_items(codec, nid);
+	unsigned int val, oldval, idx;
+
+	oldval = get_cur_hp_mic_jack_mode(codec, nid);
+	idx = ucontrol->value.enumerated.item[0];
+	if (oldval == idx)
+		return 0;
+
+	if (idx < out_jacks) {
+		if (out_jacks > 1)
+			val = idx ? PIN_HP : PIN_OUT;
+		else
+			val = PIN_HP;
+	} else {
+		idx -= out_jacks;
+		if (in_jacks > 1) {
+			unsigned int vref_caps = get_vref_caps(codec, nid);
+			val = snd_hda_codec_get_pin_target(codec, nid);
+			val &= ~(AC_PINCTL_VREFEN | PIN_HP);
+			val |= get_vref_idx(vref_caps, idx) | PIN_IN;
+		} else
+			val = snd_hda_get_default_vref(codec, nid);
+	}
+	snd_hda_set_pin_ctl_cache(codec, nid, val);
+	update_hp_automute_hook(codec);
+
+	return 1;
+}
+
+static const struct snd_kcontrol_new hp_mic_jack_mode_enum = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.info = hp_mic_jack_mode_info,
+	.get = hp_mic_jack_mode_get,
+	.put = hp_mic_jack_mode_put,
+};
+
+static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin)
+{
+	struct hda_gen_spec *spec = codec->spec;
+	struct snd_kcontrol_new *knew;
+
+	if (get_out_jack_num_items(codec, pin) <= 1 &&
+	    get_in_jack_num_items(codec, pin) <= 1)
+		return 0; /* no need */
+	knew = snd_hda_gen_add_kctl(spec, "Headphone Mic Jack Mode",
+				    &hp_mic_jack_mode_enum);
+	if (!knew)
+		return -ENOMEM;
+	knew->private_value = pin;
+	spec->hp_mic_jack_modes = 1;
+	return 0;
+}
 
 /*
  * Parse input paths
@@ -2648,7 +2859,6 @@ static int check_dyn_adc_switch(struct hda_codec *codec)
 	unsigned int ok_bits;
 	int i, n, nums;
 
- again:
 	nums = 0;
 	ok_bits = 0;
 	for (n = 0; n < spec->num_adc_nids; n++) {
@@ -2663,12 +2873,6 @@ static int check_dyn_adc_switch(struct hda_codec *codec)
 	}
 
 	if (!ok_bits) {
-		if (spec->shared_mic_hp) {
-			spec->shared_mic_hp = 0;
-			imux->num_items = 1;
-			goto again;
-		}
-
 		/* check whether ADC-switch is possible */
 		for (i = 0; i < imux->num_items; i++) {
 			for (n = 0; n < spec->num_adc_nids; n++) {
@@ -2701,7 +2905,8 @@ static int check_dyn_adc_switch(struct hda_codec *codec)
 		spec->num_adc_nids = nums;
 	}
 
-	if (imux->num_items == 1 || spec->shared_mic_hp) {
+	if (imux->num_items == 1 ||
+	    (imux->num_items == 2 && spec->hp_mic)) {
 		snd_printdd("hda-codec: reducing to a single ADC\n");
 		spec->num_adc_nids = 1; /* reduce to a single ADC */
 	}
@@ -2738,6 +2943,8 @@ static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin,
 			snd_hda_get_path_idx(codec, path);
 
 		if (!imux_added) {
+			if (spec->hp_mic_pin == pin)
+				spec->hp_mic_mux_idx = imux->num_items;
 			spec->imux_pins[imux->num_items] = pin;
 			snd_hda_add_imux_item(imux, label, cfg_idx, NULL);
 			imux_added = true;
@@ -2812,7 +3019,8 @@ static int create_input_ctls(struct hda_codec *codec)
 		val = PIN_IN;
 		if (cfg->inputs[i].type == AUTO_PIN_MIC)
 			val |= snd_hda_get_default_vref(codec, pin);
-		set_pin_target(codec, pin, val, false);
+		if (pin != spec->hp_mic_pin)
+			set_pin_target(codec, pin, val, false);
 
 		if (mixer) {
 			if (is_reachable_path(codec, pin, mixer)) {
@@ -2830,7 +3038,7 @@ static int create_input_ctls(struct hda_codec *codec)
 		if (err < 0)
 			return err;
 
-		if (spec->add_in_jack_modes) {
+		if (spec->add_jack_modes) {
 			err = create_in_jack_mode(codec, pin);
 			if (err < 0)
 				return err;
@@ -3462,8 +3670,8 @@ static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
 
 	spec->cur_mux[adc_idx] = idx;
 
-	if (spec->shared_mic_hp)
-		update_shared_mic_hp(codec, spec->cur_mux[adc_idx]);
+	if (spec->hp_mic)
+		update_hp_mic(codec, adc_idx, false);
 
 	if (spec->dyn_adc_switch)
 		dyn_adc_pcm_resetup(codec, idx);
@@ -3511,18 +3719,21 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
 
 	for (i = 0; i < num_pins; i++) {
 		hda_nid_t nid = pins[i];
-		unsigned int val;
+		unsigned int val, oldval;
 		if (!nid)
 			break;
+		oldval = snd_hda_codec_get_pin_target(codec, nid);
+		if (oldval & PIN_IN)
+			continue; /* no mute for inputs */
 		/* don't reset VREF value in case it's controlling
 		 * the amp (see alc861_fixup_asus_amp_vref_0f())
 		 */
 		if (spec->keep_vref_in_automute)
-			val = snd_hda_codec_get_pin_target(codec, nid) & ~PIN_HP;
+			val = oldval & ~PIN_HP;
 		else
 			val = 0;
 		if (!mute)
-			val |= snd_hda_codec_get_pin_target(codec, nid);
+			val |= oldval;
 		/* here we call update_pin_ctl() so that the pinctl is changed
 		 * without changing the pinctl target value;
 		 * the original target value will be still referred at the
@@ -3543,8 +3754,7 @@ void snd_hda_gen_update_outputs(struct hda_codec *codec)
 	 * in general, HP pins/amps control should be enabled in all cases,
 	 * but currently set only for master_mute, just to be safe
 	 */
-	if (!spec->shared_mic_hp) /* don't change HP-pin when shared with mic */
-		do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
+	do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
 		    spec->autocfg.hp_pins, spec->master_mute);
 
 	if (!spec->automute_speaker)
@@ -3649,10 +3859,7 @@ static void update_automute_all(struct hda_codec *codec)
 {
 	struct hda_gen_spec *spec = codec->spec;
 
-	if (spec->hp_automute_hook)
-		spec->hp_automute_hook(codec, NULL);
-	else
-		snd_hda_gen_hp_automute(codec, NULL);
+	update_hp_automute_hook(codec);
 	if (spec->line_automute_hook)
 		spec->line_automute_hook(codec, NULL);
 	else
@@ -3978,6 +4185,11 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
 		cfg = &spec->autocfg;
 	}
 
+	if (!spec->main_out_badness)
+		spec->main_out_badness = &hda_main_out_badness;
+	if (!spec->extra_out_badness)
+		spec->extra_out_badness = &hda_extra_out_badness;
+
 	fill_all_dac_nids(codec);
 
 	if (!cfg->line_outs) {
@@ -4024,7 +4236,7 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
 	err = create_loopback_mixing_ctl(codec);
 	if (err < 0)
 		return err;
-	err = create_shared_input(codec);
+	err = create_hp_mic(codec);
 	if (err < 0)
 		return err;
 	err = create_input_ctls(codec);
@@ -4050,11 +4262,9 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
 	if (err < 0)
 		return err;
 
-	if (!spec->shared_mic_hp) {
-		err = check_auto_mic_availability(codec);
-		if (err < 0)
-			return err;
-	}
+	err = check_auto_mic_availability(codec);
+	if (err < 0)
+		return err;
 
 	err = create_capture_mixers(codec);
 	if (err < 0)
@@ -4064,7 +4274,7 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
 	if (err < 0)
 		return err;
 
-	if (spec->add_out_jack_modes) {
+	if (spec->add_jack_modes) {
 		if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
 			err = create_out_jack_modes(codec, cfg->line_outs,
 						    cfg->line_out_pins);
@@ -4085,6 +4295,12 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
 	if (spec->power_down_unused)
 		codec->power_filter = snd_hda_gen_path_power_filter;
 
+	if (!spec->no_analog && spec->beep_nid) {
+		err = snd_hda_attach_beep_device(codec, spec->beep_nid);
+		if (err < 0)
+			return err;
+	}
+
 	return 1;
 }
 EXPORT_SYMBOL_HDA(snd_hda_gen_parse_auto_config);
@@ -4161,17 +4377,6 @@ int snd_hda_gen_build_controls(struct hda_codec *codec)
 
 	free_kctls(spec); /* no longer needed */
 
-	if (spec->shared_mic_hp) {
-		int err;
-		int nid = spec->autocfg.inputs[1].pin;
-		err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0);
-		if (err < 0)
-			return err;
-		err = snd_hda_jack_detect_enable(codec, nid, 0);
-		if (err < 0)
-			return err;
-	}
-
 	err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
 	if (err < 0)
 		return err;
@@ -4729,7 +4934,8 @@ static void set_output_and_unmute(struct hda_codec *codec, int path_idx)
 		return;
 	pin = path->path[path->depth - 1];
 	restore_pin_ctl(codec, pin);
-	snd_hda_activate_path(codec, path, path->active, true);
+	snd_hda_activate_path(codec, path, path->active,
+			      aamix_default(codec->spec));
 	set_pin_eapd(codec, pin, path->active);
 }
 
@@ -4779,7 +4985,8 @@ static void init_multi_io(struct hda_codec *codec)
 		if (!spec->multi_io[i].ctl_in)
 			spec->multi_io[i].ctl_in =
 				snd_hda_codec_get_pin_target(codec, pin);
-		snd_hda_activate_path(codec, path, path->active, true);
+		snd_hda_activate_path(codec, path, path->active,
+				      aamix_default(spec));
 	}
 }
 
@@ -4826,11 +5033,10 @@ static void init_input_src(struct hda_codec *codec)
 				snd_hda_activate_path(codec, path, active, false);
 			}
 		}
+		if (spec->hp_mic)
+			update_hp_mic(codec, c, true);
 	}
 
-	if (spec->shared_mic_hp)
-		update_shared_mic_hp(codec, spec->cur_mux[0]);
-
 	if (spec->cap_sync_hook)
 		spec->cap_sync_hook(codec, NULL);
 }
@@ -4911,6 +5117,7 @@ EXPORT_SYMBOL_HDA(snd_hda_gen_init);
  */
 void snd_hda_gen_free(struct hda_codec *codec)
 {
+	snd_hda_detach_beep_device(codec);
 	snd_hda_gen_spec_free(codec->spec);
 	kfree(codec->spec);
 	codec->spec = NULL;
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h
index 009b57be96d3..54e665160379 100644
--- a/sound/pci/hda/hda_generic.h
+++ b/sound/pci/hda/hda_generic.h
@@ -76,6 +76,19 @@ enum {
 	HDA_GEN_PCM_ACT_CLOSE,
 };
 
+/* DAC assignment badness table */
+struct badness_table {
+	int no_primary_dac;	/* no primary DAC */
+	int no_dac;		/* no secondary DACs */
+	int shared_primary;	/* primary DAC is shared with main output */
+	int shared_surr;	/* secondary DAC shared with main or primary */
+	int shared_clfe;	/* third DAC shared with main or primary */
+	int shared_surr_main;	/* secondary DAC sahred with main/DAC0 */
+};
+
+extern const struct badness_table hda_main_out_badness;
+extern const struct badness_table hda_extra_out_badness;
+
 struct hda_gen_spec {
 	char stream_name_analog[32];	/* analog PCM stream */
 	const struct hda_pcm_stream *stream_analog_playback;
@@ -145,7 +158,10 @@ struct hda_gen_spec {
 	hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 	hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS];
 	unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS];
+	/* shared hp/mic */
 	hda_nid_t shared_mic_vref_pin;
+	hda_nid_t hp_mic_pin;
+	int hp_mic_mux_idx;
 
 	/* DAC/ADC lists */
 	int num_all_dacs;
@@ -200,7 +216,8 @@ struct hda_gen_spec {
 
 	/* other parse behavior flags */
 	unsigned int need_dac_fix:1; /* need to limit DACs for multi channels */
-	unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */
+	unsigned int hp_mic:1; /* Allow HP as a mic-in */
+	unsigned int suppress_hp_mic_detect:1; /* Don't detect HP/mic */
 	unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */
 	unsigned int multi_cap_vol:1; /* allow multiple capture xxx volumes */
 	unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */
@@ -209,8 +226,7 @@ struct hda_gen_spec {
 	unsigned int indep_hp:1; /* independent HP supported */
 	unsigned int prefer_hp_amp:1; /* enable HP amp for speaker if any */
 	unsigned int add_stereo_mix_input:1; /* add aamix as a capture src */
-	unsigned int add_out_jack_modes:1; /* add output jack mode enum ctls */
-	unsigned int add_in_jack_modes:1; /* add input jack mode enum ctls */
+	unsigned int add_jack_modes:1; /* add i/o jack mode enum ctls */
 	unsigned int power_down_unused:1; /* power down unused widgets */
 
 	/* other internal flags */
@@ -218,10 +234,18 @@ struct hda_gen_spec {
 	unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */
 	unsigned int indep_hp_enabled:1; /* independent HP enabled */
 	unsigned int have_aamix_ctl:1;
+	unsigned int hp_mic_jack_modes:1;
+
+	/* badness tables for output path evaluations */
+	const struct badness_table *main_out_badness;
+	const struct badness_table *extra_out_badness;
 
 	/* loopback mixing mode */
 	bool aamix_mode;
 
+	/* digital beep */
+	hda_nid_t beep_nid;
+
 	/* for virtual master */
 	hda_nid_t vmaster_nid;
 	unsigned int vmaster_tlv[4];
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index bcd40ee488e3..7b213d589ef6 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1889,6 +1889,26 @@ static void azx_timecounter_init(struct snd_pcm_substream *substream,
 		tc->cycle_last = last;
 }
 
+static u64 azx_adjust_codec_delay(struct snd_pcm_substream *substream,
+				u64 nsec)
+{
+	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+	u64 codec_frames, codec_nsecs;
+
+	if (!hinfo->ops.get_delay)
+		return nsec;
+
+	codec_frames = hinfo->ops.get_delay(hinfo, apcm->codec, substream);
+	codec_nsecs = div_u64(codec_frames * 1000000000LL,
+			      substream->runtime->rate);
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		return nsec + codec_nsecs;
+
+	return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0;
+}
+
 static int azx_get_wallclock_tstamp(struct snd_pcm_substream *substream,
 				struct timespec *ts)
 {
@@ -1897,6 +1917,7 @@ static int azx_get_wallclock_tstamp(struct snd_pcm_substream *substream,
 
 	nsec = timecounter_read(&azx_dev->azx_tc);
 	nsec = div_u64(nsec, 3); /* can be optimized */
+	nsec = azx_adjust_codec_delay(substream, nsec);
 
 	*ts = ns_to_timespec(nsec);
 
@@ -2349,8 +2370,11 @@ static unsigned int azx_get_position(struct azx *chip,
 				     struct azx_dev *azx_dev,
 				     bool with_check)
 {
+	struct snd_pcm_substream *substream = azx_dev->substream;
+	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
 	unsigned int pos;
-	int stream = azx_dev->substream->stream;
+	int stream = substream->stream;
+	struct hda_pcm_stream *hinfo = apcm->hinfo[stream];
 	int delay = 0;
 
 	switch (chip->position_fix[stream]) {
@@ -2381,7 +2405,7 @@ static unsigned int azx_get_position(struct azx *chip,
 		pos = 0;
 
 	/* calculate runtime delay from LPIB */
-	if (azx_dev->substream->runtime &&
+	if (substream->runtime &&
 	    chip->position_fix[stream] == POS_FIX_POSBUF &&
 	    (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) {
 		unsigned int lpib_pos = azx_sd_readl(azx_dev, SD_LPIB);
@@ -2399,9 +2423,16 @@ static unsigned int azx_get_position(struct azx *chip,
 			delay = 0;
 			chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY;
 		}
-		azx_dev->substream->runtime->delay =
-			bytes_to_frames(azx_dev->substream->runtime, delay);
+		delay = bytes_to_frames(substream->runtime, delay);
 	}
+
+	if (substream->runtime) {
+		if (hinfo->ops.get_delay)
+			delay += hinfo->ops.get_delay(hinfo, apcm->codec,
+						      substream);
+		substream->runtime->delay = delay;
+	}
+
 	trace_azx_get_position(chip, azx_dev, pos, delay);
 	return pos;
 }
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index 1d035efeff4f..9e0a95288f46 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -394,7 +394,8 @@ static int get_unique_index(struct hda_codec *codec, const char *name, int idx)
 }
 
 static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
-			 const struct auto_pin_cfg *cfg)
+			 const struct auto_pin_cfg *cfg,
+			 const char *base_name)
 {
 	unsigned int def_conf, conn;
 	char name[44];
@@ -410,7 +411,11 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
 	phantom_jack = (conn != AC_JACK_PORT_COMPLEX) ||
 		       !is_jack_detectable(codec, nid);
 
-	snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), &idx);
+	if (base_name) {
+		strlcpy(name, base_name, sizeof(name));
+		idx = 0;
+	} else
+		snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), &idx);
 	if (phantom_jack)
 		/* Example final name: "Internal Mic Phantom Jack" */
 		strncat(name, " Phantom", sizeof(name) - strlen(name) - 1);
@@ -433,39 +438,51 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec,
 	const hda_nid_t *p;
 	int i, err;
 
+	for (i = 0; i < cfg->num_inputs; i++) {
+		/* If we have headphone mics; make sure they get the right name
+		   before grabbed by output pins */
+		if (cfg->inputs[i].is_headphone_mic) {
+			if (auto_cfg_hp_outs(cfg) == 1)
+				err = add_jack_kctl(codec, auto_cfg_hp_pins(cfg)[0],
+						    cfg, "Headphone Mic");
+			else
+				err = add_jack_kctl(codec, cfg->inputs[i].pin,
+						    cfg, "Headphone Mic");
+		} else
+			err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg,
+					    NULL);
+		if (err < 0)
+			return err;
+	}
+
 	for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) {
-		err = add_jack_kctl(codec, *p, cfg);
+		err = add_jack_kctl(codec, *p, cfg, NULL);
 		if (err < 0)
 			return err;
 	}
 	for (i = 0, p = cfg->hp_pins; i < cfg->hp_outs; i++, p++) {
 		if (*p == *cfg->line_out_pins) /* might be duplicated */
 			break;
-		err = add_jack_kctl(codec, *p, cfg);
+		err = add_jack_kctl(codec, *p, cfg, NULL);
 		if (err < 0)
 			return err;
 	}
 	for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) {
 		if (*p == *cfg->line_out_pins) /* might be duplicated */
 			break;
-		err = add_jack_kctl(codec, *p, cfg);
-		if (err < 0)
-			return err;
-	}
-	for (i = 0; i < cfg->num_inputs; i++) {
-		err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg);
+		err = add_jack_kctl(codec, *p, cfg, NULL);
 		if (err < 0)
 			return err;
 	}
 	for (i = 0, p = cfg->dig_out_pins; i < cfg->dig_outs; i++, p++) {
-		err = add_jack_kctl(codec, *p, cfg);
+		err = add_jack_kctl(codec, *p, cfg, NULL);
 		if (err < 0)
 			return err;
 	}
-	err = add_jack_kctl(codec, cfg->dig_in_pin, cfg);
+	err = add_jack_kctl(codec, cfg->dig_in_pin, cfg, NULL);
 	if (err < 0)
 		return err;
-	err = add_jack_kctl(codec, cfg->mono_out_pin, cfg);
+	err = add_jack_kctl(codec, cfg->mono_out_pin, cfg, NULL);
 	if (err < 0)
 		return err;
 	return 0;
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 83b7486c8eff..e0bf7534fa1f 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -670,6 +670,10 @@ snd_hda_check_power_state(struct hda_codec *codec, hda_nid_t nid,
 	return (state != target_state);
 }
 
+unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
+					     hda_nid_t nid,
+					     unsigned int power_state);
+
 /*
  * AMP control callbacks
  */
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index df8014b27596..977b0d878dae 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -43,7 +43,6 @@ struct ad198x_spec {
 	hda_nid_t eapd_nid;
 
 	unsigned int beep_amp;	/* beep amp value, set via set_beep_amp() */
-	hda_nid_t beep_dev_nid;
 
 #ifdef ENABLE_AD_STATIC_QUIRKS
 	const struct snd_kcontrol_new *mixers[6];
@@ -609,7 +608,7 @@ static const struct hda_codec_ops ad198x_auto_patch_ops = {
 	.build_controls = ad198x_auto_build_controls,
 	.build_pcms = snd_hda_gen_build_pcms,
 	.init = snd_hda_gen_init,
-	.free = ad198x_free,
+	.free = snd_hda_gen_free,
 	.unsol_event = snd_hda_jack_unsol_event,
 #ifdef CONFIG_PM
 	.check_power_status = snd_hda_gen_check_power_status,
@@ -638,12 +637,6 @@ static int ad198x_parse_auto_config(struct hda_codec *codec)
 	if (err < 0)
 		return err;
 
-	if (spec->beep_dev_nid) {
-		err = snd_hda_attach_beep_device(codec, spec->beep_dev_nid);
-		if (err < 0)
-			return err;
-	}
-
 	codec->patch_ops = ad198x_auto_patch_ops;
 
 	return 0;
@@ -1240,7 +1233,7 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec)
 	codec->inv_eapd = 1;
 
 	spec->gen.mixer_nid = 0x07;
-	spec->beep_dev_nid = 0x19;
+	spec->gen.beep_nid = 0x19;
 	set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
 
 	/* AD1986A has a hardware problem that it can't share a stream
@@ -1256,7 +1249,7 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec)
 
 	err = ad198x_parse_auto_config(codec);
 	if (err < 0) {
-		ad198x_free(codec);
+		snd_hda_gen_free(codec);
 		return err;
 	}
 
@@ -1673,7 +1666,7 @@ static int ad1983_parse_auto_config(struct hda_codec *codec)
 		return err;
 	spec = codec->spec;
 
-	spec->beep_dev_nid = 0x10;
+	spec->gen.beep_nid = 0x10;
 	set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
 	err = ad198x_parse_auto_config(codec);
 	if (err < 0)
@@ -1684,7 +1677,7 @@ static int ad1983_parse_auto_config(struct hda_codec *codec)
 	return 0;
 
  error:
-	ad198x_free(codec);
+	snd_hda_gen_free(codec);
 	return err;
 }
 
@@ -2187,7 +2180,7 @@ static int ad1981_parse_auto_config(struct hda_codec *codec)
 	spec = codec->spec;
 
 	spec->gen.mixer_nid = 0x0e;
-	spec->beep_dev_nid = 0x10;
+	spec->gen.beep_nid = 0x10;
 	set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
 
 	snd_hda_pick_fixup(codec, NULL, ad1981_fixup_tbl, ad1981_fixups);
@@ -2205,7 +2198,7 @@ static int ad1981_parse_auto_config(struct hda_codec *codec)
 	return 0;
 
  error:
-	ad198x_free(codec);
+	snd_hda_gen_free(codec);
 	return err;
 }
 
@@ -3236,7 +3229,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
 
 	spec->gen.mixer_nid = 0x20;
 	spec->gen.mixer_merge_nid = 0x21;
-	spec->beep_dev_nid = 0x10;
+	spec->gen.beep_nid = 0x10;
 	set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
 	err = ad198x_parse_auto_config(codec);
 	if (err < 0)
@@ -3247,7 +3240,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
 	return 0;
 
  error:
-	ad198x_free(codec);
+	snd_hda_gen_free(codec);
 	return err;
 }
 
@@ -3653,7 +3646,7 @@ static int ad1884_parse_auto_config(struct hda_codec *codec)
 	spec = codec->spec;
 
 	spec->gen.mixer_nid = 0x20;
-	spec->beep_dev_nid = 0x10;
+	spec->gen.beep_nid = 0x10;
 	set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
 
 	snd_hda_pick_fixup(codec, NULL, ad1884_fixup_tbl, ad1884_fixups);
@@ -3671,7 +3664,7 @@ static int ad1884_parse_auto_config(struct hda_codec *codec)
 	return 0;
 
  error:
-	ad198x_free(codec);
+	snd_hda_gen_free(codec);
 	return err;
 }
 
@@ -5155,7 +5148,7 @@ static int ad1882_parse_auto_config(struct hda_codec *codec)
 
 	spec->gen.mixer_nid = 0x20;
 	spec->gen.mixer_merge_nid = 0x21;
-	spec->beep_dev_nid = 0x10;
+	spec->gen.beep_nid = 0x10;
 	set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
 	err = ad198x_parse_auto_config(codec);
 	if (err < 0)
@@ -5166,7 +5159,7 @@ static int ad1882_parse_auto_config(struct hda_codec *codec)
 	return 0;
 
  error:
-	ad198x_free(codec);
+	snd_hda_gen_free(codec);
 	return err;
 }
 
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 0792b5725f9c..90ff7a3f72df 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -131,6 +131,13 @@ enum {
 /* Effects values size*/
 #define EFFECT_VALS_MAX_COUNT 12
 
+/* Latency introduced by DSP blocks in milliseconds. */
+#define DSP_CAPTURE_INIT_LATENCY        0
+#define DSP_CRYSTAL_VOICE_LATENCY       124
+#define DSP_PLAYBACK_INIT_LATENCY       13
+#define DSP_PLAY_ENHANCEMENT_LATENCY    30
+#define DSP_SPEAKER_OUT_LATENCY         7
+
 struct ct_effect {
 	char name[44];
 	hda_nid_t nid;
@@ -741,6 +748,9 @@ struct ca0132_spec {
 	long voicefx_val;
 	long cur_mic_boost;
 
+	struct hda_codec *codec;
+	struct delayed_work unsol_hp_work;
+
 #ifdef ENABLE_TUNING_CONTROLS
 	long cur_ctl_vals[TUNING_CTLS_COUNT];
 #endif
@@ -2740,6 +2750,31 @@ static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
 	return 0;
 }
 
+static unsigned int ca0132_playback_pcm_delay(struct hda_pcm_stream *info,
+			struct hda_codec *codec,
+			struct snd_pcm_substream *substream)
+{
+	struct ca0132_spec *spec = codec->spec;
+	unsigned int latency = DSP_PLAYBACK_INIT_LATENCY;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	if (spec->dsp_state != DSP_DOWNLOADED)
+		return 0;
+
+	/* Add latency if playback enhancement and either effect is enabled. */
+	if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) {
+		if ((spec->effects_switch[SURROUND - EFFECT_START_NID]) ||
+		    (spec->effects_switch[DIALOG_PLUS - EFFECT_START_NID]))
+			latency += DSP_PLAY_ENHANCEMENT_LATENCY;
+	}
+
+	/* Applying Speaker EQ adds latency as well. */
+	if (spec->cur_out_type == SPEAKER_OUT)
+		latency += DSP_SPEAKER_OUT_LATENCY;
+
+	return (latency * runtime->rate) / 1000;
+}
+
 /*
  * Digital out
  */
@@ -2808,6 +2843,23 @@ static int ca0132_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 	return 0;
 }
 
+static unsigned int ca0132_capture_pcm_delay(struct hda_pcm_stream *info,
+			struct hda_codec *codec,
+			struct snd_pcm_substream *substream)
+{
+	struct ca0132_spec *spec = codec->spec;
+	unsigned int latency = DSP_CAPTURE_INIT_LATENCY;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	if (spec->dsp_state != DSP_DOWNLOADED)
+		return 0;
+
+	if (spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID])
+		latency += DSP_CRYSTAL_VOICE_LATENCY;
+
+	return (latency * runtime->rate) / 1000;
+}
+
 /*
  * Controls stuffs.
  */
@@ -3227,6 +3279,14 @@ exit:
 	return err < 0 ? err : 0;
 }
 
+static void ca0132_unsol_hp_delayed(struct work_struct *work)
+{
+	struct ca0132_spec *spec = container_of(
+		to_delayed_work(work), struct ca0132_spec, unsol_hp_work);
+	ca0132_select_out(spec->codec);
+	snd_hda_jack_report_sync(spec->codec);
+}
+
 static void ca0132_set_dmic(struct hda_codec *codec, int enable);
 static int ca0132_mic_boost_set(struct hda_codec *codec, long val);
 static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val);
@@ -3991,7 +4051,8 @@ static struct hda_pcm_stream ca0132_pcm_analog_playback = {
 	.channels_max = 6,
 	.ops = {
 		.prepare = ca0132_playback_pcm_prepare,
-		.cleanup = ca0132_playback_pcm_cleanup
+		.cleanup = ca0132_playback_pcm_cleanup,
+		.get_delay = ca0132_playback_pcm_delay,
 	},
 };
 
@@ -4001,7 +4062,8 @@ static struct hda_pcm_stream ca0132_pcm_analog_capture = {
 	.channels_max = 2,
 	.ops = {
 		.prepare = ca0132_capture_pcm_prepare,
-		.cleanup = ca0132_capture_pcm_cleanup
+		.cleanup = ca0132_capture_pcm_cleanup,
+		.get_delay = ca0132_capture_pcm_delay,
 	},
 };
 
@@ -4399,8 +4461,7 @@ static void ca0132_process_dsp_response(struct hda_codec *codec)
 
 static void ca0132_unsol_event(struct hda_codec *codec, unsigned int res)
 {
-	snd_printdd(KERN_INFO "ca0132_unsol_event: 0x%x\n", res);
-
+	struct ca0132_spec *spec = codec->spec;
 
 	if (((res >> AC_UNSOL_RES_TAG_SHIFT) & 0x3f) == UNSOL_TAG_DSP) {
 		ca0132_process_dsp_response(codec);
@@ -4412,8 +4473,13 @@ static void ca0132_unsol_event(struct hda_codec *codec, unsigned int res)
 
 		switch (res) {
 		case UNSOL_TAG_HP:
-			ca0132_select_out(codec);
-			snd_hda_jack_report_sync(codec);
+			/* Delay enabling the HP amp, to let the mic-detection
+			 * state machine run.
+			 */
+			cancel_delayed_work_sync(&spec->unsol_hp_work);
+			queue_delayed_work(codec->bus->workq,
+					   &spec->unsol_hp_work,
+					   msecs_to_jiffies(500));
 			break;
 		case UNSOL_TAG_AMIC1:
 			ca0132_select_mic(codec);
@@ -4588,6 +4654,7 @@ static void ca0132_free(struct hda_codec *codec)
 {
 	struct ca0132_spec *spec = codec->spec;
 
+	cancel_delayed_work_sync(&spec->unsol_hp_work);
 	snd_hda_power_up(codec);
 	snd_hda_sequence_write(codec, spec->base_exit_verbs);
 	ca0132_exit_chip(codec);
@@ -4653,6 +4720,7 @@ static int patch_ca0132(struct hda_codec *codec)
 	if (!spec)
 		return -ENOMEM;
 	codec->spec = spec;
+	spec->codec = codec;
 
 	spec->num_mixers = 1;
 	spec->mixers[0] = ca0132_mixer;
@@ -4663,6 +4731,8 @@ static int patch_ca0132(struct hda_codec *codec)
 	spec->init_verbs[1] = ca0132_init_verbs1;
 	spec->num_init_verbs = 2;
 
+	INIT_DELAYED_WORK(&spec->unsol_hp_work, ca0132_unsol_hp_delayed);
+
 	ca0132_init_chip(codec);
 
 	ca0132_config(codec);
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 0d9c58f13560..bd8d46cca2b3 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -68,6 +68,7 @@ enum {
 enum {
 	CS421X_CDB4210,
 	CS421X_SENSE_B,
+	CS421X_STUMPY,
 };
 
 /* Vendor-specific processing widget */
@@ -538,6 +539,7 @@ static int patch_cs420x(struct hda_codec *codec)
 /* CS4210 board names */
 static const struct hda_model_fixup cs421x_models[] = {
 	{ .id = CS421X_CDB4210, .name = "cdb4210" },
+	{ .id = CS421X_STUMPY, .name = "stumpy" },
 	{}
 };
 
@@ -559,6 +561,17 @@ static const struct hda_pintbl cdb4210_pincfgs[] = {
 	{} /* terminator */
 };
 
+/* Stumpy ChromeBox */
+static const struct hda_pintbl stumpy_pincfgs[] = {
+	{ 0x05, 0x022120f0 },
+	{ 0x06, 0x901700f0 },
+	{ 0x07, 0x02a120f0 },
+	{ 0x08, 0x77a70037 },
+	{ 0x09, 0x77a6003e },
+	{ 0x0a, 0x434510f0 },
+	{} /* terminator */
+};
+
 /* Setup GPIO/SENSE for each board (if used) */
 static void cs421x_fixup_sense_b(struct hda_codec *codec,
 				 const struct hda_fixup *fix, int action)
@@ -578,7 +591,11 @@ static const struct hda_fixup cs421x_fixups[] = {
 	[CS421X_SENSE_B] = {
 		.type = HDA_FIXUP_FUNC,
 		.v.func = cs421x_fixup_sense_b,
-	}
+	},
+	[CS421X_STUMPY] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = stumpy_pincfgs,
+	},
 };
 
 static const struct hda_verb cs421x_coef_init_verbs[] = {
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 2a89d1eefeb6..84b81c874a4a 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -139,8 +139,12 @@ struct conexant_spec {
 
 
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
-#define set_beep_amp(spec, nid, idx, dir) \
-	((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir))
+static inline void set_beep_amp(struct conexant_spec *spec, hda_nid_t nid,
+				int idx, int dir)
+{
+	spec->gen.beep_nid = nid;
+	spec->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
+}
 /* additional beep mixers; the actual parameters are overwritten at build */
 static const struct snd_kcontrol_new cxt_beep_mixer[] = {
 	HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
@@ -2942,7 +2946,6 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD),
 	SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD),
 	SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS),
-	SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT5066_THINKPAD),
 	SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD),
 	SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS),
 	SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS),
@@ -3191,17 +3194,11 @@ static int cx_auto_build_controls(struct hda_codec *codec)
 	return 0;
 }
 
-static void cx_auto_free(struct hda_codec *codec)
-{
-	snd_hda_detach_beep_device(codec);
-	snd_hda_gen_free(codec);
-}
-
 static const struct hda_codec_ops cx_auto_patch_ops = {
 	.build_controls = cx_auto_build_controls,
 	.build_pcms = snd_hda_gen_build_pcms,
 	.init = snd_hda_gen_init,
-	.free = cx_auto_free,
+	.free = snd_hda_gen_free,
 	.unsol_event = snd_hda_jack_unsol_event,
 #ifdef CONFIG_PM
 	.check_power_status = snd_hda_gen_check_power_status,
@@ -3310,6 +3307,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
 	SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410),
 	SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410),
 	SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410),
+	SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410),
 	SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
 	SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
 	SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
@@ -3356,7 +3354,6 @@ static int patch_conexant_auto(struct hda_codec *codec)
 	switch (codec->vendor_id) {
 	case 0x14f15045:
 		codec->single_adc_amp = 1;
-		codec->power_filter = NULL; /* Needs speaker amp to D3 to avoid click */
 		break;
 	case 0x14f15047:
 		codec->pin_amp_workaround = 1;
@@ -3396,8 +3393,6 @@ static int patch_conexant_auto(struct hda_codec *codec)
 		goto error;
 
 	codec->patch_ops = cx_auto_patch_ops;
-	if (spec->beep_amp)
-		snd_hda_attach_beep_device(codec, get_amp_nid_(spec->beep_amp));
 
 	/* Some laptops with Conexant chips show stalls in S3 resume,
 	 * which falls into the single-cmd mode.
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index de8ac5c07fd0..32930e668854 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -44,16 +44,6 @@ static bool static_hdmi_pcm;
 module_param(static_hdmi_pcm, bool, 0644);
 MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
 
-/*
- * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device
- * could support N independent pipes, each of them can be connected to one or
- * more ports (DVI, HDMI or DisplayPort).
- *
- * The HDA correspondence of pipes/ports are converter/pin nodes.
- */
-#define MAX_HDMI_CVTS	8
-#define MAX_HDMI_PINS	8
-
 struct hdmi_spec_per_cvt {
 	hda_nid_t cvt_nid;
 	int assigned;
@@ -80,16 +70,17 @@ struct hdmi_spec_per_pin {
 	bool non_pcm;
 	bool chmap_set;		/* channel-map override by ALSA API? */
 	unsigned char chmap[8]; /* ALSA API channel-map */
+	char pcm_name[8];	/* filled in build_pcm callbacks */
 };
 
 struct hdmi_spec {
 	int num_cvts;
-	struct hdmi_spec_per_cvt cvts[MAX_HDMI_CVTS];
-	hda_nid_t cvt_nids[MAX_HDMI_CVTS];
+	struct snd_array cvts; /* struct hdmi_spec_per_cvt */
+	hda_nid_t cvt_nids[4]; /* only for haswell fix */
 
 	int num_pins;
-	struct hdmi_spec_per_pin pins[MAX_HDMI_PINS];
-	struct hda_pcm pcm_rec[MAX_HDMI_PINS];
+	struct snd_array pins; /* struct hdmi_spec_per_pin */
+	struct snd_array pcm_rec; /* struct hda_pcm */
 	unsigned int channels_max; /* max over all cvts */
 
 	struct hdmi_eld temp_eld;
@@ -304,12 +295,19 @@ static struct cea_channel_speaker_allocation channel_allocations[] = {
  * HDMI routines
  */
 
+#define get_pin(spec, idx) \
+	((struct hdmi_spec_per_pin *)snd_array_elem(&spec->pins, idx))
+#define get_cvt(spec, idx) \
+	((struct hdmi_spec_per_cvt  *)snd_array_elem(&spec->cvts, idx))
+#define get_pcm_rec(spec, idx) \
+	((struct hda_pcm *)snd_array_elem(&spec->pcm_rec, idx))
+
 static int pin_nid_to_pin_index(struct hdmi_spec *spec, hda_nid_t pin_nid)
 {
 	int pin_idx;
 
 	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++)
-		if (spec->pins[pin_idx].pin_nid == pin_nid)
+		if (get_pin(spec, pin_idx)->pin_nid == pin_nid)
 			return pin_idx;
 
 	snd_printk(KERN_WARNING "HDMI: pin nid %d not registered\n", pin_nid);
@@ -322,7 +320,7 @@ static int hinfo_to_pin_index(struct hdmi_spec *spec,
 	int pin_idx;
 
 	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++)
-		if (&spec->pcm_rec[pin_idx].stream[0] == hinfo)
+		if (get_pcm_rec(spec, pin_idx)->stream == hinfo)
 			return pin_idx;
 
 	snd_printk(KERN_WARNING "HDMI: hinfo %p not registered\n", hinfo);
@@ -334,7 +332,7 @@ static int cvt_nid_to_cvt_index(struct hdmi_spec *spec, hda_nid_t cvt_nid)
 	int cvt_idx;
 
 	for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++)
-		if (spec->cvts[cvt_idx].cvt_nid == cvt_nid)
+		if (get_cvt(spec, cvt_idx)->cvt_nid == cvt_nid)
 			return cvt_idx;
 
 	snd_printk(KERN_WARNING "HDMI: cvt nid %d not registered\n", cvt_nid);
@@ -352,7 +350,7 @@ static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol,
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
 
 	pin_idx = kcontrol->private_value;
-	eld = &spec->pins[pin_idx].sink_eld;
+	eld = &get_pin(spec, pin_idx)->sink_eld;
 
 	mutex_lock(&eld->lock);
 	uinfo->count = eld->eld_valid ? eld->eld_size : 0;
@@ -370,7 +368,7 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
 	int pin_idx;
 
 	pin_idx = kcontrol->private_value;
-	eld = &spec->pins[pin_idx].sink_eld;
+	eld = &get_pin(spec, pin_idx)->sink_eld;
 
 	mutex_lock(&eld->lock);
 	if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data)) {
@@ -410,11 +408,11 @@ static int hdmi_create_eld_ctl(struct hda_codec *codec, int pin_idx,
 	kctl->private_value = pin_idx;
 	kctl->id.device = device;
 
-	err = snd_hda_ctl_add(codec, spec->pins[pin_idx].pin_nid, kctl);
+	err = snd_hda_ctl_add(codec, get_pin(spec, pin_idx)->pin_nid, kctl);
 	if (err < 0)
 		return err;
 
-	spec->pins[pin_idx].eld_ctl = kctl;
+	get_pin(spec, pin_idx)->eld_ctl = kctl;
 	return 0;
 }
 
@@ -875,14 +873,14 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
 				       struct snd_pcm_substream *substream)
 {
 	struct hdmi_spec *spec = codec->spec;
-	struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+	struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
 	hda_nid_t pin_nid = per_pin->pin_nid;
 	int channels = substream->runtime->channels;
 	struct hdmi_eld *eld;
 	int ca;
 	union audio_infoframe ai;
 
-	eld = &spec->pins[pin_idx].sink_eld;
+	eld = &per_pin->sink_eld;
 	if (!eld->monitor_present)
 		return;
 
@@ -977,7 +975,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
 	if (pin_idx < 0)
 		return;
 
-	hdmi_present_sense(&spec->pins[pin_idx], 1);
+	hdmi_present_sense(get_pin(spec, pin_idx), 1);
 	snd_hda_jack_report_sync(codec);
 }
 
@@ -1020,6 +1018,41 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
 		hdmi_non_intrinsic_event(codec, res);
 }
 
+static void haswell_verify_pin_D0(struct hda_codec *codec, hda_nid_t nid)
+{
+	int pwr, lamp, ramp;
+
+	pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
+	pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT;
+	if (pwr != AC_PWRST_D0) {
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
+				    AC_PWRST_D0);
+		msleep(40);
+		pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
+		pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT;
+		snd_printd("Haswell HDMI audio: Power for pin 0x%x is now D%d\n", nid, pwr);
+	}
+
+	lamp = snd_hda_codec_read(codec, nid, 0,
+				  AC_VERB_GET_AMP_GAIN_MUTE,
+				  AC_AMP_GET_LEFT | AC_AMP_GET_OUTPUT);
+	ramp = snd_hda_codec_read(codec, nid, 0,
+				  AC_VERB_GET_AMP_GAIN_MUTE,
+				  AC_AMP_GET_RIGHT | AC_AMP_GET_OUTPUT);
+	if (lamp != ramp) {
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+				    AC_AMP_SET_RIGHT | AC_AMP_SET_OUTPUT | lamp);
+
+		lamp = snd_hda_codec_read(codec, nid, 0,
+				  AC_VERB_GET_AMP_GAIN_MUTE,
+				  AC_AMP_GET_LEFT | AC_AMP_GET_OUTPUT);
+		ramp = snd_hda_codec_read(codec, nid, 0,
+				  AC_VERB_GET_AMP_GAIN_MUTE,
+				  AC_AMP_GET_RIGHT | AC_AMP_GET_OUTPUT);
+		snd_printd("Haswell HDMI audio: Mute after set on pin 0x%x: [0x%x 0x%x]\n", nid, lamp, ramp);
+	}
+}
+
 /*
  * Callbacks
  */
@@ -1034,6 +1067,9 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
 	int pinctl;
 	int new_pinctl = 0;
 
+	if (codec->vendor_id == 0x80862807)
+		haswell_verify_pin_D0(codec, pin_nid);
+
 	if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) {
 		pinctl = snd_hda_codec_read(codec, pin_nid, 0,
 					    AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
@@ -1083,12 +1119,12 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
 	pin_idx = hinfo_to_pin_index(spec, hinfo);
 	if (snd_BUG_ON(pin_idx < 0))
 		return -EINVAL;
-	per_pin = &spec->pins[pin_idx];
+	per_pin = get_pin(spec, pin_idx);
 	eld = &per_pin->sink_eld;
 
 	/* Dynamically assign converter to stream */
 	for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
-		per_cvt = &spec->cvts[cvt_idx];
+		per_cvt = get_cvt(spec, cvt_idx);
 
 		/* Must not already be assigned */
 		if (per_cvt->assigned)
@@ -1151,7 +1187,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
 static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
 {
 	struct hdmi_spec *spec = codec->spec;
-	struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+	struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
 	hda_nid_t pin_nid = per_pin->pin_nid;
 
 	if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) {
@@ -1275,14 +1311,13 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
 	if (get_defcfg_connect(config) == AC_JACK_PORT_NONE)
 		return 0;
 
-	if (snd_BUG_ON(spec->num_pins >= MAX_HDMI_PINS))
-		return -E2BIG;
-
 	if (codec->vendor_id == 0x80862807)
 		intel_haswell_fixup_connect_list(codec, pin_nid);
 
 	pin_idx = spec->num_pins;
-	per_pin = &spec->pins[pin_idx];
+	per_pin = snd_array_new(&spec->pins);
+	if (!per_pin)
+		return -ENOMEM;
 
 	per_pin->pin_nid = pin_nid;
 	per_pin->non_pcm = false;
@@ -1299,19 +1334,16 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
 static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
 {
 	struct hdmi_spec *spec = codec->spec;
-	int cvt_idx;
 	struct hdmi_spec_per_cvt *per_cvt;
 	unsigned int chans;
 	int err;
 
-	if (snd_BUG_ON(spec->num_cvts >= MAX_HDMI_CVTS))
-		return -E2BIG;
-
 	chans = get_wcaps(codec, cvt_nid);
 	chans = get_wcaps_channels(chans);
 
-	cvt_idx = spec->num_cvts;
-	per_cvt = &spec->cvts[cvt_idx];
+	per_cvt = snd_array_new(&spec->cvts);
+	if (!per_cvt)
+		return -ENOMEM;
 
 	per_cvt->cvt_nid = cvt_nid;
 	per_cvt->channels_min = 2;
@@ -1328,7 +1360,9 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
 	if (err < 0)
 		return err;
 
-	spec->cvt_nids[spec->num_cvts++] = cvt_nid;
+	if (spec->num_cvts < ARRAY_SIZE(spec->cvt_nids))
+		spec->cvt_nids[spec->num_cvts] = cvt_nid;
+	spec->num_cvts++;
 
 	return 0;
 }
@@ -1384,13 +1418,6 @@ static int hdmi_parse_codec(struct hda_codec *codec)
 
 /*
  */
-static char *get_hdmi_pcm_name(int idx)
-{
-	static char names[MAX_HDMI_PINS][8];
-	sprintf(&names[idx][0], "HDMI %d", idx);
-	return &names[idx][0];
-}
-
 static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
 {
 	struct hda_spdif_out *spdif;
@@ -1417,7 +1444,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 	hda_nid_t cvt_nid = hinfo->nid;
 	struct hdmi_spec *spec = codec->spec;
 	int pin_idx = hinfo_to_pin_index(spec, hinfo);
-	hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid;
+	hda_nid_t pin_nid = get_pin(spec, pin_idx)->pin_nid;
 	bool non_pcm;
 
 	non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
@@ -1450,7 +1477,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
 		cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid);
 		if (snd_BUG_ON(cvt_idx < 0))
 			return -EINVAL;
-		per_cvt = &spec->cvts[cvt_idx];
+		per_cvt = get_cvt(spec, cvt_idx);
 
 		snd_BUG_ON(!per_cvt->assigned);
 		per_cvt->assigned = 0;
@@ -1459,7 +1486,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
 		pin_idx = hinfo_to_pin_index(spec, hinfo);
 		if (snd_BUG_ON(pin_idx < 0))
 			return -EINVAL;
-		per_pin = &spec->pins[pin_idx];
+		per_pin = get_pin(spec, pin_idx);
 
 		snd_hda_spdif_ctls_unassign(codec, pin_idx);
 		per_pin->chmap_set = false;
@@ -1553,7 +1580,7 @@ static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol,
 	struct hda_codec *codec = info->private_data;
 	struct hdmi_spec *spec = codec->spec;
 	int pin_idx = kcontrol->private_value;
-	struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+	struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(per_pin->chmap); i++)
@@ -1568,7 +1595,7 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol,
 	struct hda_codec *codec = info->private_data;
 	struct hdmi_spec *spec = codec->spec;
 	int pin_idx = kcontrol->private_value;
-	struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+	struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
 	unsigned int ctl_idx;
 	struct snd_pcm_substream *substream;
 	unsigned char chmap[8];
@@ -1613,9 +1640,14 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
 	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
 		struct hda_pcm *info;
 		struct hda_pcm_stream *pstr;
-
-		info = &spec->pcm_rec[pin_idx];
-		info->name = get_hdmi_pcm_name(pin_idx);
+		struct hdmi_spec_per_pin *per_pin;
+
+		per_pin = get_pin(spec, pin_idx);
+		sprintf(per_pin->pcm_name, "HDMI %d", pin_idx);
+		info = snd_array_new(&spec->pcm_rec);
+		if (!info)
+			return -ENOMEM;
+		info->name = per_pin->pcm_name;
 		info->pcm_type = HDA_PCM_TYPE_HDMI;
 		info->own_chmap = true;
 
@@ -1626,7 +1658,7 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
 	}
 
 	codec->num_pcms = spec->num_pins;
-	codec->pcm_info = spec->pcm_rec;
+	codec->pcm_info = spec->pcm_rec.list;
 
 	return 0;
 }
@@ -1635,8 +1667,8 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx)
 {
 	char hdmi_str[32] = "HDMI/DP";
 	struct hdmi_spec *spec = codec->spec;
-	struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
-	int pcmdev = spec->pcm_rec[pin_idx].device;
+	struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+	int pcmdev = get_pcm_rec(spec, pin_idx)->device;
 
 	if (pcmdev > 0)
 		sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev);
@@ -1654,7 +1686,7 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
 	int pin_idx;
 
 	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-		struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+		struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
 
 		err = generic_hdmi_build_jack(codec, pin_idx);
 		if (err < 0)
@@ -1669,9 +1701,8 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
 		snd_hda_spdif_ctls_unassign(codec, pin_idx);
 
 		/* add control for ELD Bytes */
-		err = hdmi_create_eld_ctl(codec,
-					pin_idx,
-					spec->pcm_rec[pin_idx].device);
+		err = hdmi_create_eld_ctl(codec, pin_idx,
+					  get_pcm_rec(spec, pin_idx)->device);
 
 		if (err < 0)
 			return err;
@@ -1709,7 +1740,7 @@ static int generic_hdmi_init_per_pins(struct hda_codec *codec)
 	int pin_idx;
 
 	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-		struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+		struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
 		struct hdmi_eld *eld = &per_pin->sink_eld;
 
 		per_pin->codec = codec;
@@ -1726,7 +1757,7 @@ static int generic_hdmi_init(struct hda_codec *codec)
 	int pin_idx;
 
 	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-		struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+		struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
 		hda_nid_t pin_nid = per_pin->pin_nid;
 
 		hdmi_init_pin(codec, pin_nid);
@@ -1735,13 +1766,27 @@ static int generic_hdmi_init(struct hda_codec *codec)
 	return 0;
 }
 
+static void hdmi_array_init(struct hdmi_spec *spec, int nums)
+{
+	snd_array_init(&spec->pins, sizeof(struct hdmi_spec_per_pin), nums);
+	snd_array_init(&spec->cvts, sizeof(struct hdmi_spec_per_cvt), nums);
+	snd_array_init(&spec->pcm_rec, sizeof(struct hda_pcm), nums);
+}
+
+static void hdmi_array_free(struct hdmi_spec *spec)
+{
+	snd_array_free(&spec->pins);
+	snd_array_free(&spec->cvts);
+	snd_array_free(&spec->pcm_rec);
+}
+
 static void generic_hdmi_free(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 	int pin_idx;
 
 	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-		struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+		struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
 		struct hdmi_eld *eld = &per_pin->sink_eld;
 
 		cancel_delayed_work(&per_pin->work);
@@ -1749,6 +1794,7 @@ static void generic_hdmi_free(struct hda_codec *codec)
 	}
 
 	flush_workqueue(codec->bus->workq);
+	hdmi_array_free(spec);
 	kfree(spec);
 }
 
@@ -1775,6 +1821,7 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
 
 	/* override pins connection list */
 	snd_printdd("hdmi: haswell: override pin connection 0x%x\n", nid);
+	nconns = max(spec->num_cvts, 4);
 	snd_hda_override_conn_list(codec, nid, spec->num_cvts, spec->cvt_nids);
 }
 
@@ -1855,6 +1902,7 @@ static int patch_generic_hdmi(struct hda_codec *codec)
 		return -ENOMEM;
 
 	codec->spec = spec;
+	hdmi_array_init(spec, 4);
 
 	snd_hda_pick_fixup(codec, hdmi_models, hdmi_fixup_tbl, hdmi_fixups);
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
@@ -1882,24 +1930,30 @@ static int patch_generic_hdmi(struct hda_codec *codec)
 static int simple_playback_build_pcms(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
-	struct hda_pcm *info = spec->pcm_rec;
+	struct hda_pcm *info;
 	unsigned int chans;
 	struct hda_pcm_stream *pstr;
+	struct hdmi_spec_per_cvt *per_cvt;
 
-	codec->num_pcms = 1;
-	codec->pcm_info = info;
-
-	chans = get_wcaps(codec, spec->cvts[0].cvt_nid);
+	per_cvt = get_cvt(spec, 0);
+	chans = get_wcaps(codec, per_cvt->cvt_nid);
 	chans = get_wcaps_channels(chans);
 
-	info->name = get_hdmi_pcm_name(0);
+	info = snd_array_new(&spec->pcm_rec);
+	if (!info)
+		return -ENOMEM;
+	info->name = get_pin(spec, 0)->pcm_name;
+	sprintf(info->name, "HDMI 0");
 	info->pcm_type = HDA_PCM_TYPE_HDMI;
 	pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
 	*pstr = spec->pcm_playback;
-	pstr->nid = spec->cvts[0].cvt_nid;
+	pstr->nid = per_cvt->cvt_nid;
 	if (pstr->channels_max <= 2 && chans && chans <= 16)
 		pstr->channels_max = chans;
 
+	codec->num_pcms = 1;
+	codec->pcm_info = info;
+
 	return 0;
 }
 
@@ -1919,11 +1973,12 @@ static void simple_hdmi_unsol_event(struct hda_codec *codec,
 static int simple_playback_build_controls(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
+	struct hdmi_spec_per_cvt *per_cvt;
 	int err;
 
-	err = snd_hda_create_spdif_out_ctls(codec,
-					    spec->cvts[0].cvt_nid,
-					    spec->cvts[0].cvt_nid);
+	per_cvt = get_cvt(spec, 0);
+	err = snd_hda_create_spdif_out_ctls(codec, per_cvt->cvt_nid,
+					    per_cvt->cvt_nid);
 	if (err < 0)
 		return err;
 	return simple_hdmi_build_jack(codec, 0);
@@ -1932,7 +1987,8 @@ static int simple_playback_build_controls(struct hda_codec *codec)
 static int simple_playback_init(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
-	hda_nid_t pin = spec->pins[0].pin_nid;
+	struct hdmi_spec_per_pin *per_pin = get_pin(spec, 0);
+	hda_nid_t pin = per_pin->pin_nid;
 
 	snd_hda_codec_write(codec, pin, 0,
 			    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
@@ -1948,6 +2004,7 @@ static void simple_playback_free(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 
+	hdmi_array_free(spec);
 	kfree(spec);
 }
 
@@ -2111,20 +2168,29 @@ static int patch_simple_hdmi(struct hda_codec *codec,
 			     hda_nid_t cvt_nid, hda_nid_t pin_nid)
 {
 	struct hdmi_spec *spec;
+	struct hdmi_spec_per_cvt *per_cvt;
+	struct hdmi_spec_per_pin *per_pin;
 
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (!spec)
 		return -ENOMEM;
 
 	codec->spec = spec;
+	hdmi_array_init(spec, 1);
 
 	spec->multiout.num_dacs = 0;  /* no analog */
 	spec->multiout.max_channels = 2;
 	spec->multiout.dig_out_nid = cvt_nid;
 	spec->num_cvts = 1;
 	spec->num_pins = 1;
-	spec->cvts[0].cvt_nid = cvt_nid;
-	spec->pins[0].pin_nid = pin_nid;
+	per_pin = snd_array_new(&spec->pins);
+	per_cvt = snd_array_new(&spec->cvts);
+	if (!per_pin || !per_cvt) {
+		simple_playback_free(codec);
+		return -ENOMEM;
+	}
+	per_cvt->cvt_nid = cvt_nid;
+	per_pin->pin_nid = pin_nid;
 	spec->pcm_playback = simple_pcm_playback;
 
 	codec->patch_ops = simple_hdmi_patch_ops;
@@ -2201,9 +2267,11 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
 	int i;
 	struct hdmi_spec *spec = codec->spec;
 	struct hda_spdif_out *spdif;
+	struct hdmi_spec_per_cvt *per_cvt;
 
 	mutex_lock(&codec->spdif_mutex);
-	spdif = snd_hda_spdif_out_of_nid(codec, spec->cvts[0].cvt_nid);
+	per_cvt = get_cvt(spec, 0);
+	spdif = snd_hda_spdif_out_of_nid(codec, per_cvt->cvt_nid);
 
 	chs = substream->runtime->channels;
 
@@ -2325,13 +2393,17 @@ static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 	int err = simple_playback_build_pcms(codec);
-	spec->pcm_rec[0].own_chmap = true;
+	if (!err) {
+		struct hda_pcm *info = get_pcm_rec(spec, 0);
+		info->own_chmap = true;
+	}
 	return err;
 }
 
 static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
+	struct hda_pcm *info;
 	struct snd_pcm_chmap *chmap;
 	int err;
 
@@ -2340,7 +2412,8 @@ static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec)
 		return err;
 
 	/* add channel maps */
-	err = snd_pcm_add_chmap_ctls(spec->pcm_rec[0].pcm,
+	info = get_pcm_rec(spec, 0);
+	err = snd_pcm_add_chmap_ctls(info->pcm,
 				     SNDRV_PCM_STREAM_PLAYBACK,
 				     snd_pcm_alt_chmaps, 8, 0, &chmap);
 	if (err < 0)
@@ -2395,6 +2468,7 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 					struct snd_pcm_substream *substream)
 {
 	struct hdmi_spec *spec = codec->spec;
+	struct hdmi_spec_per_cvt *per_cvt = get_cvt(spec, 0);
 	int chans = substream->runtime->channels;
 	int i, err;
 
@@ -2402,11 +2476,11 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 					  substream);
 	if (err < 0)
 		return err;
-	snd_hda_codec_write(codec, spec->cvts[0].cvt_nid, 0,
+	snd_hda_codec_write(codec, per_cvt->cvt_nid, 0,
 			    AC_VERB_SET_CVT_CHAN_COUNT, chans - 1);
 	/* FIXME: XXX */
 	for (i = 0; i < chans; i++) {
-		snd_hda_codec_write(codec, spec->cvts[0].cvt_nid, 0,
+		snd_hda_codec_write(codec, per_cvt->cvt_nid, 0,
 				    AC_VERB_SET_HDMI_CHAN_SLOT,
 				    (i << 4) | i);
 	}
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index f15c36bde540..6bf47f7326ad 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -34,7 +34,6 @@
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_auto_parser.h"
-#include "hda_beep.h"
 #include "hda_jack.h"
 #include "hda_generic.h"
 
@@ -53,6 +52,20 @@ enum {
 	ALC_INIT_GPIO3,
 };
 
+enum {
+	ALC_HEADSET_MODE_UNKNOWN,
+	ALC_HEADSET_MODE_UNPLUGGED,
+	ALC_HEADSET_MODE_HEADSET,
+	ALC_HEADSET_MODE_MIC,
+	ALC_HEADSET_MODE_HEADPHONE,
+};
+
+enum {
+	ALC_HEADSET_TYPE_UNKNOWN,
+	ALC_HEADSET_TYPE_CTIA,
+	ALC_HEADSET_TYPE_OMTP,
+};
+
 struct alc_customize_define {
 	unsigned int  sku_cfg;
 	unsigned char port_connectivity;
@@ -86,6 +99,13 @@ struct alc_spec {
 	int mute_led_polarity;
 	hda_nid_t mute_led_nid;
 
+	unsigned int gpio_led; /* used for alc269_fixup_hp_gpio_led() */
+
+	hda_nid_t headset_mic_pin;
+	hda_nid_t headphone_mic_pin;
+	int current_headset_mode;
+	int current_headset_type;
+
 	/* hooks */
 	void (*init_hook)(struct hda_codec *codec);
 #ifdef CONFIG_PM
@@ -805,17 +825,7 @@ static inline void alc_shutup(struct hda_codec *codec)
 	snd_hda_shutup_pins(codec);
 }
 
-static void alc_free(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	if (!spec)
-		return;
-
-	snd_hda_gen_spec_free(&spec->gen);
-	snd_hda_detach_beep_device(codec);
-	kfree(spec);
-}
+#define alc_free	snd_hda_gen_free
 
 #ifdef CONFIG_PM
 static void alc_power_eapd(struct hda_codec *codec)
@@ -1401,6 +1411,7 @@ static int patch_alc880(struct hda_codec *codec)
 
 	spec = codec->spec;
 	spec->gen.need_dac_fix = 1;
+	spec->gen.beep_nid = 0x01;
 
 	snd_hda_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl,
 		       alc880_fixups);
@@ -1411,12 +1422,8 @@ static int patch_alc880(struct hda_codec *codec)
 	if (err < 0)
 		goto error;
 
-	if (!spec->gen.no_analog) {
-		err = snd_hda_attach_beep_device(codec, 0x1);
-		if (err < 0)
-			goto error;
+	if (!spec->gen.no_analog)
 		set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-	}
 
 	codec->patch_ops = alc_patch_ops;
 	codec->patch_ops.unsol_event = alc880_unsol_event;
@@ -1455,6 +1462,7 @@ enum {
 	ALC260_FIXUP_HP_B1900,
 	ALC260_FIXUP_KN1,
 	ALC260_FIXUP_FSC_S7020,
+	ALC260_FIXUP_FSC_S7020_JWSE,
 };
 
 static void alc260_gpio1_automute(struct hda_codec *codec)
@@ -1516,14 +1524,17 @@ static void alc260_fixup_fsc_s7020(struct hda_codec *codec,
 				   const struct hda_fixup *fix, int action)
 {
 	struct alc_spec *spec = codec->spec;
-
-	switch (action) {
-	case HDA_FIXUP_ACT_PRE_PROBE:
-		spec->gen.add_out_jack_modes = 1;
-		break;
-	case HDA_FIXUP_ACT_PROBE:
+	if (action == HDA_FIXUP_ACT_PROBE)
 		spec->init_amp = ALC_INIT_NONE;
-		break;
+}
+
+static void alc260_fixup_fsc_s7020_jwse(struct hda_codec *codec,
+				   const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		spec->gen.add_jack_modes = 1;
+		spec->gen.hp_mic = 1;
 	}
 }
 
@@ -1586,6 +1597,12 @@ static const struct hda_fixup alc260_fixups[] = {
 		.type = HDA_FIXUP_FUNC,
 		.v.func = alc260_fixup_fsc_s7020,
 	},
+	[ALC260_FIXUP_FSC_S7020_JWSE] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc260_fixup_fsc_s7020_jwse,
+		.chained = true,
+		.chain_id = ALC260_FIXUP_FSC_S7020,
+	},
 };
 
 static const struct snd_pci_quirk alc260_fixup_tbl[] = {
@@ -1602,6 +1619,14 @@ static const struct snd_pci_quirk alc260_fixup_tbl[] = {
 	{}
 };
 
+static const struct hda_model_fixup alc260_fixup_models[] = {
+	{.id = ALC260_FIXUP_GPIO1, .name = "gpio1"},
+	{.id = ALC260_FIXUP_COEF, .name = "coef"},
+	{.id = ALC260_FIXUP_FSC_S7020, .name = "fujitsu"},
+	{.id = ALC260_FIXUP_FSC_S7020_JWSE, .name = "fujitsu-jwse"},
+	{}
+};
+
 /*
  */
 static int patch_alc260(struct hda_codec *codec)
@@ -1619,8 +1644,10 @@ static int patch_alc260(struct hda_codec *codec)
 	 * it's almost harmless.
 	 */
 	spec->gen.prefer_hp_amp = 1;
+	spec->gen.beep_nid = 0x01;
 
-	snd_hda_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
+	snd_hda_pick_fixup(codec, alc260_fixup_models, alc260_fixup_tbl,
+			   alc260_fixups);
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
 
 	/* automatic parse from the BIOS config */
@@ -1628,12 +1655,8 @@ static int patch_alc260(struct hda_codec *codec)
 	if (err < 0)
 		goto error;
 
-	if (!spec->gen.no_analog) {
-		err = snd_hda_attach_beep_device(codec, 0x1);
-		if (err < 0)
-			goto error;
+	if (!spec->gen.no_analog)
 		set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
-	}
 
 	codec->patch_ops = alc_patch_ops;
 	spec->shutup = alc_eapd_shutup;
@@ -2132,17 +2155,16 @@ static int patch_alc882(struct hda_codec *codec)
 
 	alc_auto_parse_customize_define(codec);
 
+	if (has_cdefine_beep(codec))
+		spec->gen.beep_nid = 0x01;
+
 	/* automatic parse from the BIOS config */
 	err = alc882_parse_auto_config(codec);
 	if (err < 0)
 		goto error;
 
-	if (!spec->gen.no_analog && has_cdefine_beep(codec)) {
-		err = snd_hda_attach_beep_device(codec, 0x1);
-		if (err < 0)
-			goto error;
+	if (!spec->gen.no_analog && spec->gen.beep_nid)
 		set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-	}
 
 	codec->patch_ops = alc_patch_ops;
 
@@ -2295,17 +2317,16 @@ static int patch_alc262(struct hda_codec *codec)
 
 	alc_auto_parse_customize_define(codec);
 
+	if (has_cdefine_beep(codec))
+		spec->gen.beep_nid = 0x01;
+
 	/* automatic parse from the BIOS config */
 	err = alc262_parse_auto_config(codec);
 	if (err < 0)
 		goto error;
 
-	if (!spec->gen.no_analog && has_cdefine_beep(codec)) {
-		err = snd_hda_attach_beep_device(codec, 0x1);
-		if (err < 0)
-			goto error;
+	if (!spec->gen.no_analog && spec->gen.beep_nid)
 		set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-	}
 
 	codec->patch_ops = alc_patch_ops;
 	spec->shutup = alc_eapd_shutup;
@@ -2386,16 +2407,7 @@ static const struct snd_pci_quirk alc268_fixup_tbl[] = {
 static int alc268_parse_auto_config(struct hda_codec *codec)
 {
 	static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 };
-	struct alc_spec *spec = codec->spec;
-	int err = alc_parse_auto_config(codec, NULL, alc268_ssids);
-	if (err > 0) {
-		if (!spec->gen.no_analog &&
-		    spec->gen.autocfg.speaker_pins[0] != 0x1d) {
-			add_mixer(spec, alc268_beep_mixer);
-			snd_hda_add_verbs(codec, alc268_beep_init_verbs);
-		}
-	}
-	return err;
+	return alc_parse_auto_config(codec, NULL, alc268_ssids);
 }
 
 /*
@@ -2403,7 +2415,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
 static int patch_alc268(struct hda_codec *codec)
 {
 	struct alc_spec *spec;
-	int i, has_beep, err;
+	int err;
 
 	/* ALC268 has no aa-loopback mixer */
 	err = alc_alloc_spec(codec, 0);
@@ -2411,6 +2423,7 @@ static int patch_alc268(struct hda_codec *codec)
 		return err;
 
 	spec = codec->spec;
+	spec->gen.beep_nid = 0x01;
 
 	snd_hda_pick_fixup(codec, alc268_fixup_models, alc268_fixup_tbl, alc268_fixups);
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
@@ -2420,18 +2433,10 @@ static int patch_alc268(struct hda_codec *codec)
 	if (err < 0)
 		goto error;
 
-	has_beep = 0;
-	for (i = 0; i < spec->num_mixers; i++) {
-		if (spec->mixers[i] == alc268_beep_mixer) {
-			has_beep = 1;
-			break;
-		}
-	}
-
-	if (has_beep) {
-		err = snd_hda_attach_beep_device(codec, 0x1);
-		if (err < 0)
-			goto error;
+	if (err > 0 && !spec->gen.no_analog &&
+	    spec->gen.autocfg.speaker_pins[0] != 0x1d) {
+		add_mixer(spec, alc268_beep_mixer);
+		snd_hda_add_verbs(codec, alc268_beep_init_verbs);
 		if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
 			/* override the amp caps for beep generator */
 			snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
@@ -2515,6 +2520,7 @@ enum {
 	ALC269_TYPE_ALC280,
 	ALC269_TYPE_ALC282,
 	ALC269_TYPE_ALC284,
+	ALC269_TYPE_ALC286,
 };
 
 /*
@@ -2538,6 +2544,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
 	case ALC269_TYPE_ALC269VB:
 	case ALC269_TYPE_ALC269VD:
 	case ALC269_TYPE_ALC282:
+	case ALC269_TYPE_ALC286:
 		ssids = alc269_ssids;
 		break;
 	default:
@@ -2631,7 +2638,8 @@ static void alc271_fixup_dmic(struct hda_codec *codec,
 	};
 	unsigned int cfg;
 
-	if (strcmp(codec->chip_name, "ALC271X"))
+	if (strcmp(codec->chip_name, "ALC271X") &&
+	    strcmp(codec->chip_name, "ALC269VB"))
 		return;
 	cfg = snd_hda_codec_get_pincfg(codec, 0x12);
 	if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED)
@@ -2693,6 +2701,34 @@ static void alc269_fixup_quanta_mute(struct hda_codec *codec,
 	spec->gen.automute_hook = alc269_quanta_automute;
 }
 
+static void alc269_x101_hp_automute_hook(struct hda_codec *codec,
+					 struct hda_jack_tbl *jack)
+{
+	struct alc_spec *spec = codec->spec;
+	int vref;
+	msleep(200);
+	snd_hda_gen_hp_automute(codec, jack);
+
+	vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0;
+	msleep(100);
+	snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    vref);
+	msleep(500);
+	snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    vref);
+}
+
+static void alc269_fixup_x101_headset_mic(struct hda_codec *codec,
+				     const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+		spec->gen.hp_automute_hook = alc269_x101_hp_automute_hook;
+	}
+}
+
+
 /* update mute-LED according to the speaker mute state via mic VREF pin */
 static void alc269_fixup_mic_mute_hook(void *private_data, int enabled)
 {
@@ -2757,6 +2793,356 @@ static void alc269_fixup_hp_mute_led_mic2(struct hda_codec *codec,
 	}
 }
 
+/* turn on/off mute LED per vmaster hook */
+static void alc269_fixup_hp_gpio_mute_hook(void *private_data, int enabled)
+{
+	struct hda_codec *codec = private_data;
+	struct alc_spec *spec = codec->spec;
+	unsigned int oldval = spec->gpio_led;
+
+	if (enabled)
+		spec->gpio_led &= ~0x08;
+	else
+		spec->gpio_led |= 0x08;
+	if (spec->gpio_led != oldval)
+		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+				    spec->gpio_led);
+}
+
+/* turn on/off mic-mute LED per capture hook */
+static void alc269_fixup_hp_gpio_mic_mute_hook(struct hda_codec *codec,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct alc_spec *spec = codec->spec;
+	unsigned int oldval = spec->gpio_led;
+
+	if (!ucontrol)
+		return;
+
+	if (ucontrol->value.integer.value[0] ||
+	    ucontrol->value.integer.value[1])
+		spec->gpio_led &= ~0x10;
+	else
+		spec->gpio_led |= 0x10;
+	if (spec->gpio_led != oldval)
+		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+				    spec->gpio_led);
+}
+
+static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
+				const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+	static const struct hda_verb gpio_init[] = {
+		{ 0x01, AC_VERB_SET_GPIO_MASK, 0x18 },
+		{ 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x18 },
+		{}
+	};
+
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		spec->gen.vmaster_mute.hook = alc269_fixup_hp_gpio_mute_hook;
+		spec->gen.cap_sync_hook = alc269_fixup_hp_gpio_mic_mute_hook;
+		spec->gpio_led = 0;
+		snd_hda_add_verbs(codec, gpio_init);
+	}
+}
+
+static void alc_headset_mode_unplugged(struct hda_codec *codec)
+{
+	int val;
+
+	switch (codec->vendor_id) {
+	case 0x10ec0283:
+		alc_write_coef_idx(codec, 0x1b, 0x0c0b);
+		alc_write_coef_idx(codec, 0x45, 0xc429);
+		val = alc_read_coef_idx(codec, 0x35);
+		alc_write_coef_idx(codec, 0x35, val & 0xbfff);
+		alc_write_coef_idx(codec, 0x06, 0x2104);
+		alc_write_coef_idx(codec, 0x1a, 0x0001);
+		alc_write_coef_idx(codec, 0x26, 0x0004);
+		alc_write_coef_idx(codec, 0x32, 0x42a3);
+		break;
+	case 0x10ec0292:
+		alc_write_coef_idx(codec, 0x76, 0x000e);
+		alc_write_coef_idx(codec, 0x6c, 0x2400);
+		alc_write_coef_idx(codec, 0x18, 0x7308);
+		alc_write_coef_idx(codec, 0x6b, 0xc429);
+		break;
+	case 0x10ec0668:
+		alc_write_coef_idx(codec, 0x15, 0x0d40);
+		alc_write_coef_idx(codec, 0xb7, 0x802b);
+		break;
+	}
+	snd_printdd("Headset jack set to unplugged mode.\n");
+}
+
+
+static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
+				    hda_nid_t mic_pin)
+{
+	int val;
+
+	switch (codec->vendor_id) {
+	case 0x10ec0283:
+		alc_write_coef_idx(codec, 0x45, 0xc429);
+		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+		val = alc_read_coef_idx(codec, 0x35);
+		alc_write_coef_idx(codec, 0x35, val | 1<<14);
+		alc_write_coef_idx(codec, 0x06, 0x2100);
+		alc_write_coef_idx(codec, 0x1a, 0x0021);
+		alc_write_coef_idx(codec, 0x26, 0x008c);
+		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+		break;
+	case 0x10ec0292:
+		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+		alc_write_coef_idx(codec, 0x19, 0xa208);
+		alc_write_coef_idx(codec, 0x2e, 0xacf0);
+		break;
+	case 0x10ec0668:
+		alc_write_coef_idx(codec, 0x11, 0x0001);
+		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+		alc_write_coef_idx(codec, 0xb7, 0x802b);
+		alc_write_coef_idx(codec, 0xb5, 0x1040);
+		val = alc_read_coef_idx(codec, 0xc3);
+		alc_write_coef_idx(codec, 0xc3, val | 1<<12);
+		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+		break;
+	}
+	snd_printdd("Headset jack set to mic-in mode.\n");
+}
+
+static void alc_headset_mode_default(struct hda_codec *codec)
+{
+	switch (codec->vendor_id) {
+	case 0x10ec0283:
+		alc_write_coef_idx(codec, 0x06, 0x2100);
+		alc_write_coef_idx(codec, 0x32, 0x4ea3);
+		break;
+	case 0x10ec0292:
+		alc_write_coef_idx(codec, 0x76, 0x000e);
+		alc_write_coef_idx(codec, 0x6c, 0x2400);
+		alc_write_coef_idx(codec, 0x6b, 0xc429);
+		alc_write_coef_idx(codec, 0x18, 0x7308);
+		break;
+	case 0x10ec0668:
+		alc_write_coef_idx(codec, 0x11, 0x0041);
+		alc_write_coef_idx(codec, 0x15, 0x0d40);
+		alc_write_coef_idx(codec, 0xb7, 0x802b);
+		break;
+	}
+	snd_printdd("Headset jack set to headphone (default) mode.\n");
+}
+
+/* Iphone type */
+static void alc_headset_mode_ctia(struct hda_codec *codec)
+{
+	switch (codec->vendor_id) {
+	case 0x10ec0283:
+		alc_write_coef_idx(codec, 0x45, 0xd429);
+		alc_write_coef_idx(codec, 0x1b, 0x0c2b);
+		alc_write_coef_idx(codec, 0x32, 0x4ea3);
+		break;
+	case 0x10ec0292:
+		alc_write_coef_idx(codec, 0x6b, 0xd429);
+		alc_write_coef_idx(codec, 0x76, 0x0008);
+		alc_write_coef_idx(codec, 0x18, 0x7388);
+		break;
+	case 0x10ec0668:
+		alc_write_coef_idx(codec, 0x15, 0x0d60);
+		alc_write_coef_idx(codec, 0xc3, 0x0000);
+		break;
+	}
+	snd_printdd("Headset jack set to iPhone-style headset mode.\n");
+}
+
+/* Nokia type */
+static void alc_headset_mode_omtp(struct hda_codec *codec)
+{
+	switch (codec->vendor_id) {
+	case 0x10ec0283:
+		alc_write_coef_idx(codec, 0x45, 0xe429);
+		alc_write_coef_idx(codec, 0x1b, 0x0c2b);
+		alc_write_coef_idx(codec, 0x32, 0x4ea3);
+		break;
+	case 0x10ec0292:
+		alc_write_coef_idx(codec, 0x6b, 0xe429);
+		alc_write_coef_idx(codec, 0x76, 0x0008);
+		alc_write_coef_idx(codec, 0x18, 0x7388);
+		break;
+	case 0x10ec0668:
+		alc_write_coef_idx(codec, 0x15, 0x0d50);
+		alc_write_coef_idx(codec, 0xc3, 0x0000);
+		break;
+	}
+	snd_printdd("Headset jack set to Nokia-style headset mode.\n");
+}
+
+static void alc_determine_headset_type(struct hda_codec *codec)
+{
+	int val;
+	bool is_ctia = false;
+	struct alc_spec *spec = codec->spec;
+
+	switch (codec->vendor_id) {
+	case 0x10ec0283:
+		alc_write_coef_idx(codec, 0x45, 0xd029);
+		msleep(300);
+		val = alc_read_coef_idx(codec, 0x46);
+		is_ctia = (val & 0x0070) == 0x0070;
+		break;
+	case 0x10ec0292:
+		alc_write_coef_idx(codec, 0x6b, 0xd429);
+		msleep(300);
+		val = alc_read_coef_idx(codec, 0x6c);
+		is_ctia = (val & 0x001c) == 0x001c;
+		break;
+	case 0x10ec0668:
+		alc_write_coef_idx(codec, 0x11, 0x0001);
+		alc_write_coef_idx(codec, 0xb7, 0x802b);
+		alc_write_coef_idx(codec, 0x15, 0x0d60);
+		alc_write_coef_idx(codec, 0xc3, 0x0c00);
+		msleep(300);
+		val = alc_read_coef_idx(codec, 0xbe);
+		is_ctia = (val & 0x1c02) == 0x1c02;
+		break;
+	}
+
+	snd_printdd("Headset jack detected iPhone-style headset: %s\n",
+		    is_ctia ? "yes" : "no");
+	spec->current_headset_type = is_ctia ? ALC_HEADSET_TYPE_CTIA : ALC_HEADSET_TYPE_OMTP;
+}
+
+static void alc_update_headset_mode(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]];
+	hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
+
+	int new_headset_mode;
+
+	if (!snd_hda_jack_detect(codec, hp_pin))
+		new_headset_mode = ALC_HEADSET_MODE_UNPLUGGED;
+	else if (mux_pin == spec->headset_mic_pin)
+		new_headset_mode = ALC_HEADSET_MODE_HEADSET;
+	else if (mux_pin == spec->headphone_mic_pin)
+		new_headset_mode = ALC_HEADSET_MODE_MIC;
+	else
+		new_headset_mode = ALC_HEADSET_MODE_HEADPHONE;
+
+	if (new_headset_mode == spec->current_headset_mode)
+		return;
+
+	switch (new_headset_mode) {
+	case ALC_HEADSET_MODE_UNPLUGGED:
+		alc_headset_mode_unplugged(codec);
+		spec->gen.hp_jack_present = false;
+		break;
+	case ALC_HEADSET_MODE_HEADSET:
+		if (spec->current_headset_type == ALC_HEADSET_TYPE_UNKNOWN)
+			alc_determine_headset_type(codec);
+		if (spec->current_headset_type == ALC_HEADSET_TYPE_CTIA)
+			alc_headset_mode_ctia(codec);
+		else if (spec->current_headset_type == ALC_HEADSET_TYPE_OMTP)
+			alc_headset_mode_omtp(codec);
+		spec->gen.hp_jack_present = true;
+		break;
+	case ALC_HEADSET_MODE_MIC:
+		alc_headset_mode_mic_in(codec, hp_pin, spec->headphone_mic_pin);
+		spec->gen.hp_jack_present = false;
+		break;
+	case ALC_HEADSET_MODE_HEADPHONE:
+		alc_headset_mode_default(codec);
+		spec->gen.hp_jack_present = true;
+		break;
+	}
+	if (new_headset_mode != ALC_HEADSET_MODE_MIC) {
+		snd_hda_set_pin_ctl_cache(codec, hp_pin,
+					  AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
+		if (spec->headphone_mic_pin)
+			snd_hda_set_pin_ctl_cache(codec, spec->headphone_mic_pin,
+						  PIN_VREFHIZ);
+	}
+	spec->current_headset_mode = new_headset_mode;
+
+	snd_hda_gen_update_outputs(codec);
+}
+
+static void alc_update_headset_mode_hook(struct hda_codec *codec,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	alc_update_headset_mode(codec);
+}
+
+static void alc_update_headset_jack_cb(struct hda_codec *codec, struct hda_jack_tbl *jack)
+{
+	struct alc_spec *spec = codec->spec;
+	spec->current_headset_type = ALC_HEADSET_MODE_UNKNOWN;
+	snd_hda_gen_hp_automute(codec, jack);
+}
+
+static void alc_probe_headset_mode(struct hda_codec *codec)
+{
+	int i;
+	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+
+	/* Find mic pins */
+	for (i = 0; i < cfg->num_inputs; i++) {
+		if (cfg->inputs[i].is_headset_mic && !spec->headset_mic_pin)
+			spec->headset_mic_pin = cfg->inputs[i].pin;
+		if (cfg->inputs[i].is_headphone_mic && !spec->headphone_mic_pin)
+			spec->headphone_mic_pin = cfg->inputs[i].pin;
+	}
+
+	spec->gen.cap_sync_hook = alc_update_headset_mode_hook;
+	spec->gen.automute_hook = alc_update_headset_mode;
+	spec->gen.hp_automute_hook = alc_update_headset_jack_cb;
+}
+
+static void alc_fixup_headset_mode(struct hda_codec *codec,
+				const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+
+	switch (action) {
+	case HDA_FIXUP_ACT_PRE_PROBE:
+		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC | HDA_PINCFG_HEADPHONE_MIC;
+		break;
+	case HDA_FIXUP_ACT_PROBE:
+		alc_probe_headset_mode(codec);
+		break;
+	case HDA_FIXUP_ACT_INIT:
+		spec->current_headset_mode = 0;
+		alc_update_headset_mode(codec);
+		break;
+	}
+}
+
+static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
+				const struct hda_fixup *fix, int action)
+{
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		struct alc_spec *spec = codec->spec;
+		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+	}
+	else
+		alc_fixup_headset_mode(codec, fix, action);
+}
+
+static void alc_fixup_headset_mode_alc668(struct hda_codec *codec,
+				const struct hda_fixup *fix, int action)
+{
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		int val;
+		alc_write_coef_idx(codec, 0xc4, 0x8000);
+		val = alc_read_coef_idx(codec, 0xc2);
+		alc_write_coef_idx(codec, 0xc2, val & 0xfe);
+		snd_hda_set_pin_ctl_cache(codec, 0x18, 0);
+	}
+	alc_fixup_headset_mode(codec, fix, action);
+}
+
 static void alc271_hp_gate_mic_jack(struct hda_codec *codec,
 				    const struct hda_fixup *fix,
 				    int action)
@@ -2772,6 +3158,38 @@ static void alc271_hp_gate_mic_jack(struct hda_codec *codec,
 	}
 }
 
+static void alc269_fixup_limit_int_mic_boost(struct hda_codec *codec,
+					     const struct hda_fixup *fix,
+					     int action)
+{
+	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+	int i;
+
+	/* The mic boosts on level 2 and 3 are too noisy
+	   on the internal mic input.
+	   Therefore limit the boost to 0 or 1. */
+
+	if (action != HDA_FIXUP_ACT_PROBE)
+		return;
+
+	for (i = 0; i < cfg->num_inputs; i++) {
+		hda_nid_t nid = cfg->inputs[i].pin;
+		unsigned int defcfg;
+		if (cfg->inputs[i].type != AUTO_PIN_MIC)
+			continue;
+		defcfg = snd_hda_codec_get_pincfg(codec, nid);
+		if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT)
+			continue;
+
+		snd_hda_override_amp_caps(codec, nid, HDA_INPUT,
+					  (0x00 << AC_AMPCAP_OFFSET_SHIFT) |
+					  (0x01 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+					  (0x2f << AC_AMPCAP_STEP_SIZE_SHIFT) |
+					  (0 << AC_AMPCAP_MUTE_SHIFT));
+	}
+}
+
 enum {
 	ALC269_FIXUP_SONY_VAIO,
 	ALC275_FIXUP_SONY_VAIO_GPIO2,
@@ -2792,11 +3210,21 @@ enum {
 	ALC269_FIXUP_HP_MUTE_LED,
 	ALC269_FIXUP_HP_MUTE_LED_MIC1,
 	ALC269_FIXUP_HP_MUTE_LED_MIC2,
+	ALC269_FIXUP_HP_GPIO_LED,
 	ALC269_FIXUP_INV_DMIC,
 	ALC269_FIXUP_LENOVO_DOCK,
 	ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT,
+	ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+	ALC269_FIXUP_DELL2_MIC_NO_PRESENCE,
+	ALC269_FIXUP_HEADSET_MODE,
+	ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC,
+	ALC269_FIXUP_ASUS_X101_FUNC,
+	ALC269_FIXUP_ASUS_X101_VERB,
+	ALC269_FIXUP_ASUS_X101,
 	ALC271_FIXUP_AMIC_MIC2,
 	ALC271_FIXUP_HP_GATE_MIC_JACK,
+	ALC269_FIXUP_ACER_AC700,
+	ALC269_FIXUP_LIMIT_INT_MIC_BOOST,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -2931,6 +3359,10 @@ static const struct hda_fixup alc269_fixups[] = {
 		.type = HDA_FIXUP_FUNC,
 		.v.func = alc269_fixup_hp_mute_led_mic2,
 	},
+	[ALC269_FIXUP_HP_GPIO_LED] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc269_fixup_hp_gpio_led,
+	},
 	[ALC269_FIXUP_INV_DMIC] = {
 		.type = HDA_FIXUP_FUNC,
 		.v.func = alc_fixup_inv_dmic_0x12,
@@ -2949,6 +3381,59 @@ static const struct hda_fixup alc269_fixups[] = {
 		.type = HDA_FIXUP_FUNC,
 		.v.func = alc269_fixup_pincfg_no_hp_to_lineout,
 	},
+	[ALC269_FIXUP_DELL1_MIC_NO_PRESENCE] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+			{ 0x1a, 0x01a1913d }, /* use as headphone mic, without its own jack detect */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC269_FIXUP_HEADSET_MODE
+	},
+	[ALC269_FIXUP_DELL2_MIC_NO_PRESENCE] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x16, 0x21014020 }, /* dock line out */
+			{ 0x19, 0x21a19030 }, /* dock mic */
+			{ 0x1a, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
+	},
+	[ALC269_FIXUP_HEADSET_MODE] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_headset_mode,
+	},
+	[ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_headset_mode_no_hp_mic,
+	},
+	[ALC269_FIXUP_ASUS_X101_FUNC] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc269_fixup_x101_headset_mic,
+	},
+	[ALC269_FIXUP_ASUS_X101_VERB] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+			{0x20, AC_VERB_SET_COEF_INDEX, 0x08},
+			{0x20, AC_VERB_SET_PROC_COEF,  0x0310},
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC269_FIXUP_ASUS_X101_FUNC
+	},
+	[ALC269_FIXUP_ASUS_X101] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x18, 0x04a1182c }, /* Headset mic */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC269_FIXUP_ASUS_X101_VERB
+	},
 	[ALC271_FIXUP_AMIC_MIC2] = {
 		.type = HDA_FIXUP_PINS,
 		.v.pins = (const struct hda_pintbl[]) {
@@ -2965,29 +3450,72 @@ static const struct hda_fixup alc269_fixups[] = {
 		.chained = true,
 		.chain_id = ALC271_FIXUP_AMIC_MIC2,
 	},
+	[ALC269_FIXUP_ACER_AC700] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x12, 0x99a3092f }, /* int-mic */
+			{ 0x14, 0x99130110 }, /* speaker */
+			{ 0x18, 0x03a11c20 }, /* mic */
+			{ 0x1e, 0x0346101e }, /* SPDIF1 */
+			{ 0x21, 0x0321101f }, /* HP out */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC271_FIXUP_DMIC,
+	},
+	[ALC269_FIXUP_LIMIT_INT_MIC_BOOST] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc269_fixup_limit_int_mic_boost,
+	},
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC),
 	SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC),
+	SND_PCI_QUIRK(0x1028, 0x05bd, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05be, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05c4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05c5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05c6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05c7, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05c8, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05c9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05ca, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05cb, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05e9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05ea, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05eb, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05ec, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05ed, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05ee, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05f3, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05f4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05f5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
 	SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
+	SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED),
 	SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED),
+	SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+	SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
 	SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_DMIC),
 	SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_DMIC),
+	SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
 	SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
 	SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC),
-	SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
+	SND_PCI_QUIRK(0x1043, 0x1c23, "Asus X55U", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
 	SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
 	SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
 	SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
 	SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
+	SND_PCI_QUIRK(0x1043, 0x8516, "ASUS X101CH", ALC269_FIXUP_ASUS_X101),
 	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),
 	SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
 	SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
+	SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700),
 	SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK),
 	SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK),
 	SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
@@ -3063,6 +3591,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
 	{.id = ALC271_FIXUP_DMIC, .name = "alc271-dmic"},
 	{.id = ALC269_FIXUP_INV_DMIC, .name = "inv-dmic"},
 	{.id = ALC269_FIXUP_LENOVO_DOCK, .name = "lenovo-dock"},
+	{.id = ALC269_FIXUP_HP_GPIO_LED, .name = "hp-gpio-led"},
 	{}
 };
 
@@ -3131,6 +3660,9 @@ static int patch_alc269(struct hda_codec *codec)
 
 	alc_auto_parse_customize_define(codec);
 
+	if (has_cdefine_beep(codec))
+		spec->gen.beep_nid = 0x01;
+
 	switch (codec->vendor_id) {
 	case 0x10ec0269:
 		spec->codec_variant = ALC269_TYPE_ALC269VA;
@@ -3172,6 +3704,9 @@ static int patch_alc269(struct hda_codec *codec)
 	case 0x10ec0292:
 		spec->codec_variant = ALC269_TYPE_ALC284;
 		break;
+	case 0x10ec0286:
+		spec->codec_variant = ALC269_TYPE_ALC286;
+		break;
 	}
 
 	/* automatic parse from the BIOS config */
@@ -3179,12 +3714,8 @@ static int patch_alc269(struct hda_codec *codec)
 	if (err < 0)
 		goto error;
 
-	if (!spec->gen.no_analog && has_cdefine_beep(codec)) {
-		err = snd_hda_attach_beep_device(codec, 0x1);
-		if (err < 0)
-			goto error;
+	if (!spec->gen.no_analog && spec->gen.beep_nid)
 		set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
-	}
 
 	codec->patch_ops = alc_patch_ops;
 #ifdef CONFIG_PM
@@ -3292,6 +3823,7 @@ static int patch_alc861(struct hda_codec *codec)
 		return err;
 
 	spec = codec->spec;
+	spec->gen.beep_nid = 0x23;
 
 	snd_hda_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
@@ -3301,12 +3833,8 @@ static int patch_alc861(struct hda_codec *codec)
 	if (err < 0)
 		goto error;
 
-	if (!spec->gen.no_analog) {
-		err = snd_hda_attach_beep_device(codec, 0x23);
-		if (err < 0)
-			goto error;
+	if (!spec->gen.no_analog)
 		set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
-	}
 
 	codec->patch_ops = alc_patch_ops;
 #ifdef CONFIG_PM
@@ -3387,6 +3915,7 @@ static int patch_alc861vd(struct hda_codec *codec)
 		return err;
 
 	spec = codec->spec;
+	spec->gen.beep_nid = 0x23;
 
 	snd_hda_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
@@ -3396,12 +3925,8 @@ static int patch_alc861vd(struct hda_codec *codec)
 	if (err < 0)
 		goto error;
 
-	if (!spec->gen.no_analog) {
-		err = snd_hda_attach_beep_device(codec, 0x23);
-		if (err < 0)
-			goto error;
+	if (!spec->gen.no_analog)
 		set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-	}
 
 	codec->patch_ops = alc_patch_ops;
 
@@ -3480,6 +4005,8 @@ enum {
 	ALC662_FIXUP_NO_JACK_DETECT,
 	ALC662_FIXUP_ZOTAC_Z68,
 	ALC662_FIXUP_INV_DMIC,
+	ALC668_FIXUP_DELL_MIC_NO_PRESENCE,
+	ALC668_FIXUP_HEADSET_MODE,
 };
 
 static const struct hda_fixup alc662_fixups[] = {
@@ -3640,6 +4167,20 @@ static const struct hda_fixup alc662_fixups[] = {
 		.type = HDA_FIXUP_FUNC,
 		.v.func = alc_fixup_inv_dmic_0x12,
 	},
+	[ALC668_FIXUP_DELL_MIC_NO_PRESENCE] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
+			{ 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC668_FIXUP_HEADSET_MODE
+	},
+	[ALC668_FIXUP_HEADSET_MODE] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_headset_mode_alc668,
+	},
 };
 
 static const struct snd_pci_quirk alc662_fixup_tbl[] = {
@@ -3648,6 +4189,8 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
 	SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC),
 	SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
+	SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
 	SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
 	SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
 	SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
@@ -3784,10 +4327,14 @@ static int patch_alc662(struct hda_codec *codec)
 
 	alc_auto_parse_customize_define(codec);
 
+	if (has_cdefine_beep(codec))
+		spec->gen.beep_nid = 0x01;
+
 	if ((alc_get_coef0(codec) & (1 << 14)) &&
 	    codec->bus->pci->subsystem_vendor == 0x1025 &&
 	    spec->cdefine.platform_type == 1) {
-		if (alc_codec_rename(codec, "ALC272X") < 0)
+		err = alc_codec_rename(codec, "ALC272X");
+		if (err < 0)
 			goto error;
 	}
 
@@ -3796,10 +4343,7 @@ static int patch_alc662(struct hda_codec *codec)
 	if (err < 0)
 		goto error;
 
-	if (!spec->gen.no_analog && has_cdefine_beep(codec)) {
-		err = snd_hda_attach_beep_device(codec, 0x1);
-		if (err < 0)
-			goto error;
+	if (!spec->gen.no_analog && spec->gen.beep_nid) {
 		switch (codec->vendor_id) {
 		case 0x10ec0662:
 			set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
@@ -3878,6 +4422,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {
 	{ .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 },
 	{ .id = 0x10ec0283, .name = "ALC283", .patch = patch_alc269 },
 	{ .id = 0x10ec0284, .name = "ALC284", .patch = patch_alc269 },
+	{ .id = 0x10ec0286, .name = "ALC286", .patch = patch_alc269 },
 	{ .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 },
 	{ .id = 0x10ec0292, .name = "ALC292", .patch = patch_alc269 },
 	{ .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index dafe04ae8c72..1d9d6427e0bf 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -211,7 +211,6 @@ struct sigmatel_spec {
 
 	/* beep widgets */
 	hda_nid_t anabeep_nid;
-	hda_nid_t digbeep_nid;
 
 	/* SPDIF-out mux */
 	const char * const *spdif_labels;
@@ -3529,8 +3528,12 @@ static int stac_parse_auto_config(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec = codec->spec;
 	int err;
+	int flags = 0;
 
-	err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
+	if (spec->headset_jack)
+		flags |= HDA_PINCFG_HEADSET_MIC;
+
+	err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, flags);
 	if (err < 0)
 		return err;
 
@@ -3560,16 +3563,13 @@ static int stac_parse_auto_config(struct hda_codec *codec)
 
 	/* setup digital beep controls and input device */
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
-	if (spec->digbeep_nid > 0) {
-		hda_nid_t nid = spec->digbeep_nid;
+	if (spec->gen.beep_nid) {
+		hda_nid_t nid = spec->gen.beep_nid;
 		unsigned int caps;
 
 		err = stac_auto_create_beep_ctls(codec, nid);
 		if (err < 0)
 			return err;
-		err = snd_hda_attach_beep_device(codec, nid);
-		if (err < 0)
-			return err;
 		if (codec->beep) {
 			/* IDT/STAC codecs have linear beep tone parameter */
 			codec->beep->linear_tone = spec->linear_tone_beep;
@@ -3657,17 +3657,7 @@ static void stac_shutup(struct hda_codec *codec)
 				~spec->eapd_mask);
 }
 
-static void stac_free(struct hda_codec *codec)
-{
-	struct sigmatel_spec *spec = codec->spec;
-
-	if (!spec)
-		return;
-
-	snd_hda_gen_spec_free(&spec->gen);
-	kfree(spec);
-	snd_hda_detach_beep_device(codec);
-}
+#define stac_free	snd_hda_gen_free
 
 #ifdef CONFIG_PROC_FS
 static void stac92hd_proc_hook(struct snd_info_buffer *buffer,
@@ -3797,6 +3787,7 @@ static int patch_stac9200(struct hda_codec *codec)
 	spec->gen.own_eapd_ctl = 1;
 
 	codec->patch_ops = stac_patch_ops;
+	codec->power_filter = snd_hda_codec_eapd_power_filter;
 
 	snd_hda_add_verbs(codec, stac9200_eapd_init);
 
@@ -3884,7 +3875,7 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
 	spec->aloopback_mask = 0x01;
 	spec->aloopback_shift = 8;
 
-	spec->digbeep_nid = 0x1c;
+	spec->gen.beep_nid = 0x1c; /* digital beep */
 
 	/* GPIO0 High = Enable EAPD */
 	spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
@@ -3968,7 +3959,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
 	spec->gen.power_down_unused = 1;
 	spec->gen.mixer_nid = 0x1b;
 
-	spec->digbeep_nid = 0x21;
+	spec->gen.beep_nid = 0x21; /* digital beep */
 	spec->pwr_nids = stac92hd83xxx_pwr_nids;
 	spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
 	spec->default_polarity = -1; /* no default cfg */
@@ -4016,7 +4007,7 @@ static int patch_stac92hd95(struct hda_codec *codec)
 	spec->gen.own_eapd_ctl = 1;
 	spec->gen.power_down_unused = 1;
 
-	spec->digbeep_nid = 0x19;
+	spec->gen.beep_nid = 0x19; /* digital beep */
 	spec->pwr_nids = stac92hd95_pwr_nids;
 	spec->num_pwrs = ARRAY_SIZE(stac92hd95_pwr_nids);
 	spec->default_polarity = -1; /* no default cfg */
@@ -4091,7 +4082,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
 	spec->aloopback_shift = 0;
 
 	spec->powerdown_adcs = 1;
-	spec->digbeep_nid = 0x26;
+	spec->gen.beep_nid = 0x26; /* digital beep */
 	spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
 	spec->pwr_nids = stac92hd71bxx_pwr_nids;
 
@@ -4173,7 +4164,7 @@ static int patch_stac927x(struct hda_codec *codec)
 	spec->have_spdif_mux = 1;
 	spec->spdif_labels = stac927x_spdif_labels;
 
-	spec->digbeep_nid = 0x23;
+	spec->gen.beep_nid = 0x23; /* digital beep */
 
 	/* GPIO0 High = Enable EAPD */
 	spec->eapd_mask = spec->gpio_mask = 0x01;
@@ -4232,7 +4223,7 @@ static int patch_stac9205(struct hda_codec *codec)
 	spec->gen.own_eapd_ctl = 1;
 	spec->have_spdif_mux = 1;
 
-	spec->digbeep_nid = 0x23;
+	spec->gen.beep_nid = 0x23; /* digital beep */
 
 	snd_hda_add_verbs(codec, stac9205_core_init);
 	spec->aloopback_ctl = &stac9205_loopback;
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index c35338a8771d..e0dadcf2030d 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -626,11 +626,31 @@ static void via_set_jack_unsol_events(struct hda_codec *codec)
 	}
 }
 
+static const struct badness_table via_main_out_badness = {
+	.no_primary_dac = 0x10000,
+	.no_dac = 0x4000,
+	.shared_primary = 0x10000,
+	.shared_surr = 0x20,
+	.shared_clfe = 0x20,
+	.shared_surr_main = 0x20,
+};
+static const struct badness_table via_extra_out_badness = {
+	.no_primary_dac = 0x4000,
+	.no_dac = 0x4000,
+	.shared_primary = 0x12,
+	.shared_surr = 0x20,
+	.shared_clfe = 0x20,
+	.shared_surr_main = 0x10,
+};
+
 static int via_parse_auto_config(struct hda_codec *codec)
 {
 	struct via_spec *spec = codec->spec;
 	int err;
 
+	spec->gen.main_out_badness = &via_main_out_badness;
+	spec->gen.extra_out_badness = &via_extra_out_badness;
+
 	err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
 	if (err < 0)
 		return err;
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 223c3d9cc69e..9ea05e956474 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -969,6 +969,7 @@ static int snd_hdspm_create_pcm(struct snd_card *card,
 				struct hdspm *hdspm);
 
 static inline void snd_hdspm_initialize_midi_flush(struct hdspm *hdspm);
+static inline int hdspm_get_pll_freq(struct hdspm *hdspm);
 static int hdspm_update_simple_mixer_controls(struct hdspm *hdspm);
 static int hdspm_autosync_ref(struct hdspm *hdspm);
 static int snd_hdspm_set_defaults(struct hdspm *hdspm);
@@ -1075,6 +1076,20 @@ static int snd_hdspm_use_is_exclusive(struct hdspm *hdspm)
 	return ret;
 }
 
+/* round arbitary sample rates to commonly known rates */
+static int hdspm_round_frequency(int rate)
+{
+	if (rate < 38050)
+		return 32000;
+	if (rate < 46008)
+		return 44100;
+	else
+		return 48000;
+}
+
+static int hdspm_tco_sync_check(struct hdspm *hdspm);
+static int hdspm_sync_in_sync_check(struct hdspm *hdspm);
+
 /* check for external sample rate */
 static int hdspm_external_sample_rate(struct hdspm *hdspm)
 {
@@ -1216,22 +1231,45 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
 				break;
 			}
 
-			/* QS and DS rates normally can not be detected
-			 * automatically by the card. Only exception is MADI
-			 * in 96k frame mode.
-			 *
-			 * So if we read SS values (32 .. 48k), check for
-			 * user-provided DS/QS bits in the control register
-			 * and multiply the base frequency accordingly.
-			 */
-			if (rate <= 48000) {
-				if (hdspm->control_register & HDSPM_QuadSpeed)
-					rate *= 4;
-				else if (hdspm->control_register &
-						HDSPM_DoubleSpeed)
-					rate *= 2;
+		} /* endif HDSPM_madiLock */
+
+		/* check sample rate from TCO or SYNC_IN */
+		{
+			bool is_valid_input = 0;
+			bool has_sync = 0;
+
+			syncref = hdspm_autosync_ref(hdspm);
+			if (HDSPM_AUTOSYNC_FROM_TCO == syncref) {
+				is_valid_input = 1;
+				has_sync = (HDSPM_SYNC_CHECK_SYNC ==
+					hdspm_tco_sync_check(hdspm));
+			} else if (HDSPM_AUTOSYNC_FROM_SYNC_IN == syncref) {
+				is_valid_input = 1;
+				has_sync = (HDSPM_SYNC_CHECK_SYNC ==
+					hdspm_sync_in_sync_check(hdspm));
+			}
+
+			if (is_valid_input && has_sync) {
+				rate = hdspm_round_frequency(
+					hdspm_get_pll_freq(hdspm));
 			}
 		}
+
+		/* QS and DS rates normally can not be detected
+		 * automatically by the card. Only exception is MADI
+		 * in 96k frame mode.
+		 *
+		 * So if we read SS values (32 .. 48k), check for
+		 * user-provided DS/QS bits in the control register
+		 * and multiply the base frequency accordingly.
+		 */
+		if (rate <= 48000) {
+			if (hdspm->control_register & HDSPM_QuadSpeed)
+				rate *= 4;
+			else if (hdspm->control_register &
+					HDSPM_DoubleSpeed)
+				rate *= 2;
+		}
 		break;
 	}
 
@@ -1979,16 +2017,25 @@ static void hdspm_midi_tasklet(unsigned long arg)
 /* get the system sample rate which is set */
 
 
+static inline int hdspm_get_pll_freq(struct hdspm *hdspm)
+{
+	unsigned int period, rate;
+
+	period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ);
+	rate = hdspm_calc_dds_value(hdspm, period);
+
+	return rate;
+}
+
 /**
  * Calculate the real sample rate from the
  * current DDS value.
  **/
 static int hdspm_get_system_sample_rate(struct hdspm *hdspm)
 {
-	unsigned int period, rate;
+	unsigned int rate;
 
-	period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ);
-	rate = hdspm_calc_dds_value(hdspm, period);
+	rate = hdspm_get_pll_freq(hdspm);
 
 	if (rate > 207000) {
 		/* Unreasonable high sample rate as seen on PCI MADI cards. */
@@ -2128,6 +2175,16 @@ static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx)
 	return (status >> (idx*4)) & 0xF;
 }
 
+#define ENUMERATED_CTL_INFO(info, texts) \
+{ \
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; \
+	uinfo->count = 1; \
+	uinfo->value.enumerated.items = ARRAY_SIZE(texts); \
+	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]); \
+}
+
 
 
 #define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
@@ -2143,14 +2200,7 @@ static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx)
 static int snd_hdspm_info_autosync_sample_rate(struct snd_kcontrol *kcontrol,
 					       struct snd_ctl_elem_info *uinfo)
 {
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 10;
-
-	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
-	strcpy(uinfo->value.enumerated.name,
-			texts_freq[uinfo->value.enumerated.item]);
+	ENUMERATED_CTL_INFO(uinfo, texts_freq);
 	return 0;
 }
 
@@ -2316,15 +2366,7 @@ static int snd_hdspm_info_system_clock_mode(struct snd_kcontrol *kcontrol,
 					    struct snd_ctl_elem_info *uinfo)
 {
 	static char *texts[] = { "Master", "AutoSync" };
-
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 2;
-	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]);
+	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
 
@@ -2888,6 +2930,112 @@ static int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
+
+
+#define HDSPM_TCO_VIDEO_INPUT_FORMAT(xname, xindex) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+	.name = xname, \
+	.access = SNDRV_CTL_ELEM_ACCESS_READ |\
+		SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+	.info = snd_hdspm_info_tco_video_input_format, \
+	.get = snd_hdspm_get_tco_video_input_format, \
+}
+
+static int snd_hdspm_info_tco_video_input_format(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
+{
+	static char *texts[] = {"No video", "NTSC", "PAL"};
+	ENUMERATED_CTL_INFO(uinfo, texts);
+	return 0;
+}
+
+static int snd_hdspm_get_tco_video_input_format(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	u32 status;
+	int ret = 0;
+
+	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+	status = hdspm_read(hdspm, HDSPM_RD_TCO + 4);
+	switch (status & (HDSPM_TCO1_Video_Input_Format_NTSC |
+			HDSPM_TCO1_Video_Input_Format_PAL)) {
+	case HDSPM_TCO1_Video_Input_Format_NTSC:
+		/* ntsc */
+		ret = 1;
+		break;
+	case HDSPM_TCO1_Video_Input_Format_PAL:
+		/* pal */
+		ret = 2;
+		break;
+	default:
+		/* no video */
+		ret = 0;
+		break;
+	}
+	ucontrol->value.enumerated.item[0] = ret;
+	return 0;
+}
+
+
+
+#define HDSPM_TCO_LTC_FRAMES(xname, xindex) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+	.name = xname, \
+	.access = SNDRV_CTL_ELEM_ACCESS_READ |\
+		SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+	.info = snd_hdspm_info_tco_ltc_frames, \
+	.get = snd_hdspm_get_tco_ltc_frames, \
+}
+
+static int snd_hdspm_info_tco_ltc_frames(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
+{
+	static char *texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps",
+				"30 fps"};
+	ENUMERATED_CTL_INFO(uinfo, texts);
+	return 0;
+}
+
+static int hdspm_tco_ltc_frames(struct hdspm *hdspm)
+{
+	u32 status;
+	int ret = 0;
+
+	status = hdspm_read(hdspm, HDSPM_RD_TCO + 4);
+	if (status & HDSPM_TCO1_LTC_Input_valid) {
+		switch (status & (HDSPM_TCO1_LTC_Format_LSB |
+					HDSPM_TCO1_LTC_Format_MSB)) {
+		case 0:
+			/* 24 fps */
+			ret = 1;
+			break;
+		case HDSPM_TCO1_LTC_Format_LSB:
+			/* 25 fps */
+			ret = 2;
+			break;
+		case HDSPM_TCO1_LTC_Format_MSB:
+			/* 25 fps */
+			ret = 3;
+			break;
+		default:
+			/* 30 fps */
+			ret = 4;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int snd_hdspm_get_tco_ltc_frames(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.enumerated.item[0] = hdspm_tco_ltc_frames(hdspm);
+	return 0;
+}
+
 #define HDSPM_TOGGLE_SETTING(xname, xindex) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
 	.name = xname, \
@@ -2974,17 +3122,7 @@ static int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol,
 				       struct snd_ctl_elem_info *uinfo)
 {
 	static char *texts[] = { "optical", "coaxial" };
-
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 2;
-
-	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]);
-
+	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
 
@@ -3046,17 +3184,7 @@ static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol,
 				  struct snd_ctl_elem_info *uinfo)
 {
 	static char *texts[] = { "Single", "Double" };
-
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 2;
-
-	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]);
-
+	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
 
@@ -3129,17 +3257,7 @@ static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol,
 				       struct snd_ctl_elem_info *uinfo)
 {
 	static char *texts[] = { "Single", "Double", "Quad" };
-
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 3;
-
-	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]);
-
+	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
 
@@ -3215,17 +3333,7 @@ static int snd_hdspm_info_madi_speedmode(struct snd_kcontrol *kcontrol,
 				       struct snd_ctl_elem_info *uinfo)
 {
 	static char *texts[] = { "Single", "Double", "Quad" };
-
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 3;
-
-	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]);
-
+	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
 
@@ -3445,19 +3553,30 @@ static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol,
 	.get = snd_hdspm_get_sync_check \
 }
 
+#define HDSPM_TCO_LOCK_CHECK(xname, xindex) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+	.name = xname, \
+	.private_value = xindex, \
+	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+	.info = snd_hdspm_tco_info_lock_check, \
+	.get = snd_hdspm_get_sync_check \
+}
+
+
 
 static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol,
 				     struct snd_ctl_elem_info *uinfo)
 {
 	static char *texts[] = { "No Lock", "Lock", "Sync", "N/A" };
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 4;
-	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]);
+	ENUMERATED_CTL_INFO(uinfo, texts);
+	return 0;
+}
+
+static int snd_hdspm_tco_info_lock_check(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_info *uinfo)
+{
+	static char *texts[] = { "No Lock", "Lock" };
+	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
 
@@ -3590,6 +3709,14 @@ static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx)
 	return 0;
 }
 
+static int hdspm_tco_input_check(struct hdspm *hdspm, u32 mask)
+{
+	u32 status;
+	status = hdspm_read(hdspm, HDSPM_RD_TCO + 4);
+
+	return (status & mask) ? 1 : 0;
+}
+
 
 static int hdspm_tco_sync_check(struct hdspm *hdspm)
 {
@@ -3697,6 +3824,22 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol,
 
 	}
 
+	if (hdspm->tco) {
+		switch (kcontrol->private_value) {
+		case 11:
+			/* Check TCO for lock state of its current input */
+			val = hdspm_tco_input_check(hdspm, HDSPM_TCO1_TCO_lock);
+			break;
+		case 12:
+			/* Check TCO for valid time code on LTC input. */
+			val = hdspm_tco_input_check(hdspm,
+				HDSPM_TCO1_LTC_Input_valid);
+			break;
+		default:
+			break;
+		}
+	}
+
 	if (-1 == val)
 		val = 3;
 
@@ -3813,17 +3956,7 @@ static int snd_hdspm_info_tco_sample_rate(struct snd_kcontrol *kcontrol,
 					  struct snd_ctl_elem_info *uinfo)
 {
 	static char *texts[] = { "44.1 kHz", "48 kHz" };
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 2;
-
-	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]);
-
+	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
 
@@ -3869,17 +4002,7 @@ static int snd_hdspm_info_tco_pull(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_info *uinfo)
 {
 	static char *texts[] = { "0", "+ 0.1 %", "- 0.1 %", "+ 4 %", "- 4 %" };
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 5;
-
-	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]);
-
+	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
 
@@ -3924,17 +4047,7 @@ static int snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol *kcontrol,
 					     struct snd_ctl_elem_info *uinfo)
 {
 	static char *texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" };
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 3;
-
-	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]);
-
+	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
 
@@ -3981,17 +4094,7 @@ static int snd_hdspm_info_tco_frame_rate(struct snd_kcontrol *kcontrol,
 {
 	static char *texts[] = { "24 fps", "25 fps", "29.97fps",
 		"29.97 dfps", "30 fps", "30 dfps" };
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 6;
-
-	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]);
-
+	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
 
@@ -4037,17 +4140,7 @@ static int snd_hdspm_info_tco_sync_source(struct snd_kcontrol *kcontrol,
 					  struct snd_ctl_elem_info *uinfo)
 {
 	static char *texts[] = { "LTC", "Video", "WCK" };
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 3;
-
-	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]);
-
+	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
 
@@ -4145,6 +4238,7 @@ static struct snd_kcontrol_new snd_hdspm_controls_madi[] = {
 	HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 3),
 	HDSPM_TOGGLE_SETTING("Line Out", HDSPM_LineOut),
 	HDSPM_TOGGLE_SETTING("TX 64 channels mode", HDSPM_TX_64ch),
+	HDSPM_TOGGLE_SETTING("Disable 96K frames", HDSPM_SMUX),
 	HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms),
 	HDSPM_TOGGLE_SETTING("Safe Mode", HDSPM_AutoInp),
 	HDSPM_INPUT_SELECT("Input Select", 0),
@@ -4272,7 +4366,11 @@ static struct snd_kcontrol_new snd_hdspm_controls_tco[] = {
 	HDSPM_TCO_WCK_CONVERSION("TCO WCK Conversion", 0),
 	HDSPM_TCO_FRAME_RATE("TCO Frame Rate", 0),
 	HDSPM_TCO_SYNC_SOURCE("TCO Sync Source", 0),
-	HDSPM_TCO_WORD_TERM("TCO Word Term", 0)
+	HDSPM_TCO_WORD_TERM("TCO Word Term", 0),
+	HDSPM_TCO_LOCK_CHECK("TCO Input Check", 11),
+	HDSPM_TCO_LOCK_CHECK("TCO LTC Valid", 12),
+	HDSPM_TCO_LTC_FRAMES("TCO Detected Frame Rate", 0),
+	HDSPM_TCO_VIDEO_INPUT_FORMAT("Video Input Format", 0)
 };
 
 
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 5da8ca7aee05..9e675c76436c 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -29,6 +29,10 @@ config SND_SOC_AC97_BUS
 config SND_SOC_DMAENGINE_PCM
 	bool
 
+config SND_SOC_GENERIC_DMAENGINE_PCM
+	bool
+	select SND_SOC_DMAENGINE_PCM
+
 # All the supported SoCs
 source "sound/soc/atmel/Kconfig"
 source "sound/soc/au1x/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 99f32f7c0692..197b6ae54c8d 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -5,6 +5,10 @@ ifneq ($(CONFIG_SND_SOC_DMAENGINE_PCM),)
 snd-soc-core-objs += soc-dmaengine-pcm.o
 endif
 
+ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
+snd-soc-core-objs += soc-generic-dmaengine-pcm.o
+endif
+
 obj-$(CONFIG_SND_SOC)	+= snd-soc-core.o
 obj-$(CONFIG_SND_SOC)	+= codecs/
 obj-$(CONFIG_SND_SOC)	+= generic/
diff --git a/sound/soc/atmel/atmel-pcm-dma.c b/sound/soc/atmel/atmel-pcm-dma.c
index 30184a4a147a..1d38fd0bc4e2 100644
--- a/sound/soc/atmel/atmel-pcm-dma.c
+++ b/sound/soc/atmel/atmel-pcm-dma.c
@@ -67,9 +67,10 @@ static const struct snd_pcm_hardware atmel_pcm_dma_hardware = {
 static void atmel_pcm_dma_irq(u32 ssc_sr,
 	struct snd_pcm_substream *substream)
 {
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct atmel_pcm_dma_params *prtd;
 
-	prtd = snd_dmaengine_pcm_get_data(substream);
+	prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
 	if (ssc_sr & prtd->mask->ssc_error) {
 		if (snd_pcm_running(substream))
@@ -104,15 +105,13 @@ static bool filter(struct dma_chan *chan, void *slave)
 }
 
 static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
+	struct snd_pcm_hw_params *params, struct atmel_pcm_dma_params *prtd)
 {
-	struct atmel_pcm_dma_params *prtd;
 	struct ssc_device *ssc;
 	struct dma_chan *dma_chan;
 	struct dma_slave_config slave_config;
 	int ret;
 
-	prtd = snd_dmaengine_pcm_get_data(substream);
 	ssc = prtd->ssc;
 
 	ret = snd_hwparams_to_dma_slave_config(substream, params,
@@ -130,8 +129,6 @@ static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream,
 		slave_config.src_maxburst = 1;
 	}
 
-	slave_config.device_fc = false;
-
 	dma_chan = snd_dmaengine_pcm_get_chan(substream);
 	if (dmaengine_slave_config(dma_chan, &slave_config)) {
 		pr_err("atmel-pcm: failed to configure dma channel\n");
@@ -158,15 +155,13 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
 	if (ssc->pdev)
 		sdata = ssc->pdev->dev.platform_data;
 
-	ret = snd_dmaengine_pcm_open(substream, filter, sdata);
+	ret = snd_dmaengine_pcm_open_request_chan(substream, filter, sdata);
 	if (ret) {
 		pr_err("atmel-pcm: dmaengine pcm open failed\n");
 		return -EINVAL;
 	}
 
-	snd_dmaengine_pcm_set_data(substream, prtd);
-
-	ret = atmel_pcm_configure_dma(substream, params);
+	ret = atmel_pcm_configure_dma(substream, params, prtd);
 	if (ret) {
 		pr_err("atmel-pcm: failed to configure dmai\n");
 		goto err;
@@ -176,15 +171,16 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
 
 	return 0;
 err:
-	snd_dmaengine_pcm_close(substream);
+	snd_dmaengine_pcm_close_release_chan(substream);
 	return ret;
 }
 
 static int atmel_pcm_dma_prepare(struct snd_pcm_substream *substream)
 {
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct atmel_pcm_dma_params *prtd;
 
-	prtd = snd_dmaengine_pcm_get_data(substream);
+	prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
 	ssc_writex(prtd->ssc->regs, SSC_IER, prtd->mask->ssc_error);
 	ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_enable);
@@ -199,16 +195,9 @@ static int atmel_pcm_open(struct snd_pcm_substream *substream)
 	return 0;
 }
 
-static int atmel_pcm_close(struct snd_pcm_substream *substream)
-{
-	snd_dmaengine_pcm_close(substream);
-
-	return 0;
-}
-
 static struct snd_pcm_ops atmel_pcm_ops = {
 	.open		= atmel_pcm_open,
-	.close		= atmel_pcm_close,
+	.close		= snd_dmaengine_pcm_close_release_chan,
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= atmel_pcm_hw_params,
 	.prepare	= atmel_pcm_dma_prepare,
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index e13580d6c476..f3fdfa07fcb9 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -533,6 +533,49 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
 		break;
 
 	case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
+		/*
+		 * DSP/PCM Mode A format, CODEC supplies BCLK and LRC clocks.
+		 *
+		 * The SSC transmit clock is obtained from the BCLK signal on
+		 * on the TK line, and the SSC receive clock is
+		 * generated from the transmit clock.
+		 *
+		 * Data is transferred on first BCLK after LRC pulse rising
+		 * edge.If stereo, the right channel data is contiguous with
+		 * the left channel data.
+		 */
+		rcmr =	  SSC_BF(RCMR_PERIOD, 0)
+			| SSC_BF(RCMR_STTDLY, START_DELAY)
+			| SSC_BF(RCMR_START, SSC_START_RISING_RF)
+			| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
+			| SSC_BF(RCMR_CKO, SSC_CKO_NONE)
+			| SSC_BF(RCMR_CKS, SSC_CKS_PIN);
+
+		rfmr =	  SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+			| SSC_BF(RFMR_FSOS, SSC_FSOS_NONE)
+			| SSC_BF(RFMR_FSLEN, 0)
+			| SSC_BF(RFMR_DATNB, (channels - 1))
+			| SSC_BIT(RFMR_MSBF)
+			| SSC_BF(RFMR_LOOP, 0)
+			| SSC_BF(RFMR_DATLEN, (bits - 1));
+
+		tcmr =	  SSC_BF(TCMR_PERIOD, 0)
+			| SSC_BF(TCMR_STTDLY, START_DELAY)
+			| SSC_BF(TCMR_START, SSC_START_RISING_RF)
+			| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
+			| SSC_BF(TCMR_CKO, SSC_CKO_NONE)
+			| SSC_BF(TCMR_CKS, SSC_CKS_PIN);
+
+		tfmr =	  SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+			| SSC_BF(TFMR_FSDEN, 0)
+			| SSC_BF(TFMR_FSOS, SSC_FSOS_NONE)
+			| SSC_BF(TFMR_FSLEN, 0)
+			| SSC_BF(TFMR_DATNB, (channels - 1))
+			| SSC_BIT(TFMR_MSBF)
+			| SSC_BF(TFMR_DATDEF, 0)
+			| SSC_BF(TFMR_DATLEN, (bits - 1));
+		break;
+
 	default:
 		printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n",
 			ssc_p->daifmt);
@@ -707,13 +750,18 @@ static struct snd_soc_dai_driver atmel_ssc_dai = {
 		.ops = &atmel_ssc_dai_ops,
 };
 
+static const struct snd_soc_component_driver atmel_ssc_component = {
+	.name		= "atmel-ssc",
+};
+
 static int asoc_ssc_init(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct ssc_device *ssc = platform_get_drvdata(pdev);
 	int ret;
 
-	ret = snd_soc_register_dai(dev, &atmel_ssc_dai);
+	ret = snd_soc_register_component(dev, &atmel_ssc_component,
+					 &atmel_ssc_dai, 1);
 	if (ret) {
 		dev_err(dev, "Could not register DAI: %d\n", ret);
 		goto err;
@@ -732,7 +780,7 @@ static int asoc_ssc_init(struct device *dev)
 	return 0;
 
 err_unregister_dai:
-	snd_soc_unregister_dai(dev);
+	snd_soc_unregister_component(dev);
 err:
 	return ret;
 }
@@ -747,7 +795,7 @@ static void asoc_ssc_exit(struct device *dev)
 	else
 		atmel_pcm_pdc_platform_unregister(dev);
 
-	snd_soc_unregister_dai(dev);
+	snd_soc_unregister_component(dev);
 }
 
 /**
diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c
index ea7d9d157022..44b8dcecf571 100644
--- a/sound/soc/au1x/ac97c.c
+++ b/sound/soc/au1x/ac97c.c
@@ -223,6 +223,10 @@ static struct snd_soc_dai_driver au1xac97c_dai_driver = {
 	.ops			= &alchemy_ac97c_ops,
 };
 
+static const struct snd_soc_component_driver au1xac97c_component = {
+	.name		= "au1xac97c",
+};
+
 static int au1xac97c_drvprobe(struct platform_device *pdev)
 {
 	int ret;
@@ -268,7 +272,8 @@ static int au1xac97c_drvprobe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, ctx);
 
-	ret = snd_soc_register_dai(&pdev->dev, &au1xac97c_dai_driver);
+	ret = snd_soc_register_component(&pdev->dev, &au1xac97c_component,
+					 &au1xac97c_dai_driver, 1);
 	if (ret)
 		return ret;
 
@@ -280,7 +285,7 @@ static int au1xac97c_drvremove(struct platform_device *pdev)
 {
 	struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev);
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	WR(ctx, AC97_ENABLE, EN_D);	/* clock off, disable */
 
diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c
index 072448afc219..b3f37f6edbcb 100644
--- a/sound/soc/au1x/i2sc.c
+++ b/sound/soc/au1x/i2sc.c
@@ -225,6 +225,10 @@ static struct snd_soc_dai_driver au1xi2s_dai_driver = {
 	.ops = &au1xi2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver au1xi2s_component = {
+	.name		= "au1xi2s",
+};
+
 static int au1xi2s_drvprobe(struct platform_device *pdev)
 {
 	struct resource *iores, *dmares;
@@ -260,14 +264,15 @@ static int au1xi2s_drvprobe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, ctx);
 
-	return snd_soc_register_dai(&pdev->dev, &au1xi2s_dai_driver);
+	return snd_soc_register_component(&pdev->dev, &au1xi2s_component,
+					  &au1xi2s_dai_driver, 1);
 }
 
 static int au1xi2s_drvremove(struct platform_device *pdev)
 {
 	struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev);
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	WR(ctx, I2S_ENABLE, EN_D);	/* clock off, disable */
 
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index 6ba07e365967..8f1862aa7333 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -361,6 +361,10 @@ static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
 	.ops = &au1xpsc_ac97_dai_ops,
 };
 
+static const struct snd_soc_component_driver au1xpsc_ac97_component = {
+	.name		= "au1xpsc-ac97",
+};
+
 static int au1xpsc_ac97_drvprobe(struct platform_device *pdev)
 {
 	int ret;
@@ -419,7 +423,8 @@ static int au1xpsc_ac97_drvprobe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, wd);
 
-	ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
+	ret = snd_soc_register_component(&pdev->dev, &au1xpsc_ac97_component,
+					 &wd->dai_drv, 1);
 	if (ret)
 		return ret;
 
@@ -431,7 +436,7 @@ static int au1xpsc_ac97_drvremove(struct platform_device *pdev)
 {
 	struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	/* disable PSC completely */
 	au_writel(0, AC97_CFG(wd));
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c
index 360b4e50d7c8..fe923a7bdc39 100644
--- a/sound/soc/au1x/psc-i2s.c
+++ b/sound/soc/au1x/psc-i2s.c
@@ -288,6 +288,10 @@ static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = {
 	.ops = &au1xpsc_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver au1xpsc_i2s_component = {
+	.name		= "au1xpsc-i2s",
+};
+
 static int au1xpsc_i2s_drvprobe(struct platform_device *pdev)
 {
 	struct resource *iores, *dmares;
@@ -350,14 +354,15 @@ static int au1xpsc_i2s_drvprobe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, wd);
 
-	return snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
+	return snd_soc_register_component(&pdev->dev, &au1xpsc_i2s_component,
+					  &wd->dai_drv, 1);
 }
 
 static int au1xpsc_i2s_drvremove(struct platform_device *pdev)
 {
 	struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	au_writel(0, I2S_CFG(wd));
 	au_sync();
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c
index 8e41bcb020eb..490217325975 100644
--- a/sound/soc/blackfin/bf5xx-ac97.c
+++ b/sound/soc/blackfin/bf5xx-ac97.c
@@ -282,6 +282,10 @@ static struct snd_soc_dai_driver bfin_ac97_dai = {
 		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
 };
 
+static const struct snd_soc_component_driver bfin_ac97_component = {
+	.name		= "bfin-ac97",
+};
+
 static int asoc_bfin_ac97_probe(struct platform_device *pdev)
 {
 	struct sport_device *sport_handle;
@@ -331,7 +335,8 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
 		goto sport_config_err;
 	}
 
-	ret = snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai);
+	ret = snd_soc_register_component(&pdev->dev, &bfin_ac97_component,
+					 &bfin_ac97_dai, 1);
 	if (ret) {
 		pr_err("Failed to register DAI: %d\n", ret);
 		goto sport_config_err;
@@ -356,7 +361,7 @@ static int asoc_bfin_ac97_remove(struct platform_device *pdev)
 {
 	struct sport_device *sport_handle = platform_get_drvdata(pdev);
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	sport_done(sport_handle);
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
 	gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c
index 168d88bccb41..dd0c2a4f83a3 100644
--- a/sound/soc/blackfin/bf5xx-i2s.c
+++ b/sound/soc/blackfin/bf5xx-i2s.c
@@ -245,6 +245,10 @@ static struct snd_soc_dai_driver bf5xx_i2s_dai = {
 	.ops = &bf5xx_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver bf5xx_i2s_component = {
+	.name		= "bf5xx-i2s",
+};
+
 static int bf5xx_i2s_probe(struct platform_device *pdev)
 {
 	struct sport_device *sport_handle;
@@ -257,7 +261,8 @@ static int bf5xx_i2s_probe(struct platform_device *pdev)
 		return -ENODEV;
 
 	/* register with the ASoC layers */
-	ret = snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai);
+	ret = snd_soc_register_component(&pdev->dev, &bf5xx_i2s_component,
+					 &bf5xx_i2s_dai, 1);
 	if (ret) {
 		pr_err("Failed to register DAI: %d\n", ret);
 		sport_done(sport_handle);
@@ -273,7 +278,7 @@ static int bf5xx_i2s_remove(struct platform_device *pdev)
 
 	pr_debug("%s enter\n", __func__);
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	sport_done(sport_handle);
 
 	return 0;
diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c
index c1e516ec53ad..69e9a3e935bd 100644
--- a/sound/soc/blackfin/bf5xx-tdm.c
+++ b/sound/soc/blackfin/bf5xx-tdm.c
@@ -249,6 +249,10 @@ static struct snd_soc_dai_driver bf5xx_tdm_dai = {
 	.ops = &bf5xx_tdm_dai_ops,
 };
 
+static const struct snd_soc_component_driver bf5xx_tdm_component = {
+	.name		= "bf5xx-tdm",
+};
+
 static int bfin_tdm_probe(struct platform_device *pdev)
 {
 	struct sport_device *sport_handle;
@@ -282,7 +286,8 @@ static int bfin_tdm_probe(struct platform_device *pdev)
 		goto sport_config_err;
 	}
 
-	ret = snd_soc_register_dai(&pdev->dev, &bf5xx_tdm_dai);
+	ret = snd_soc_register_component(&pdev->dev, &bf5xx_tdm_component,
+					 &bf5xx_tdm_dai, 1);
 	if (ret) {
 		pr_err("Failed to register DAI: %d\n", ret);
 		goto sport_config_err;
@@ -299,7 +304,7 @@ static int bfin_tdm_remove(struct platform_device *pdev)
 {
 	struct sport_device *sport_handle = platform_get_drvdata(pdev);
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	sport_done(sport_handle);
 
 	return 0;
diff --git a/sound/soc/blackfin/bf6xx-i2s.c b/sound/soc/blackfin/bf6xx-i2s.c
index 8f337972f438..c02405cc007d 100644
--- a/sound/soc/blackfin/bf6xx-i2s.c
+++ b/sound/soc/blackfin/bf6xx-i2s.c
@@ -186,6 +186,10 @@ static struct snd_soc_dai_driver bfin_i2s_dai = {
 	.ops = &bfin_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver bfin_i2s_component = {
+	.name		= "bfin-i2s",
+};
+
 static int bfin_i2s_probe(struct platform_device *pdev)
 {
 	struct sport_device *sport;
@@ -197,7 +201,8 @@ static int bfin_i2s_probe(struct platform_device *pdev)
 		return -ENODEV;
 
 	/* register with the ASoC layers */
-	ret = snd_soc_register_dai(dev, &bfin_i2s_dai);
+	ret = snd_soc_register_component(dev, &bfin_i2s_component,
+					 &bfin_i2s_dai, 1);
 	if (ret) {
 		dev_err(dev, "Failed to register DAI: %d\n", ret);
 		sport_delete(sport);
@@ -212,7 +217,7 @@ static int bfin_i2s_remove(struct platform_device *pdev)
 {
 	struct sport_device *sport = platform_get_drvdata(pdev);
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	sport_delete(sport);
 
 	return 0;
diff --git a/sound/soc/cirrus/edb93xx.c b/sound/soc/cirrus/edb93xx.c
index 5db68cf7b281..c43fb214558a 100644
--- a/sound/soc/cirrus/edb93xx.c
+++ b/sound/soc/cirrus/edb93xx.c
@@ -27,7 +27,6 @@
 #include <sound/soc.h>
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
-#include "ep93xx-pcm.h"
 
 static int edb93xx_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params)
diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c
index 1738d28fb04f..7798fbd5e81d 100644
--- a/sound/soc/cirrus/ep93xx-ac97.c
+++ b/sound/soc/cirrus/ep93xx-ac97.c
@@ -23,7 +23,6 @@
 #include <sound/soc.h>
 
 #include <linux/platform_data/dma-ep93xx.h>
-#include "ep93xx-pcm.h"
 
 /*
  * Per channel (1-4) registers.
@@ -101,14 +100,16 @@ struct ep93xx_ac97_info {
 /* currently ALSA only supports a single AC97 device */
 static struct ep93xx_ac97_info *ep93xx_ac97_info;
 
-static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_out = {
+static struct ep93xx_dma_data ep93xx_ac97_pcm_out = {
 	.name		= "ac97-pcm-out",
 	.dma_port	= EP93XX_DMA_AAC1,
+	.direction	= DMA_MEM_TO_DEV,
 };
 
-static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_in = {
+static struct ep93xx_dma_data ep93xx_ac97_pcm_in = {
 	.name		= "ac97-pcm-in",
 	.dma_port	= EP93XX_DMA_AAC1,
+	.direction	= DMA_DEV_TO_MEM,
 };
 
 static inline unsigned ep93xx_ac97_read_reg(struct ep93xx_ac97_info *info,
@@ -316,7 +317,7 @@ static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream,
 static int ep93xx_ac97_startup(struct snd_pcm_substream *substream,
 			       struct snd_soc_dai *dai)
 {
-	struct ep93xx_pcm_dma_params *dma_data;
+	struct ep93xx_dma_data *dma_data;
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		dma_data = &ep93xx_ac97_pcm_out;
@@ -353,6 +354,10 @@ static struct snd_soc_dai_driver ep93xx_ac97_dai = {
 	.ops			= &ep93xx_ac97_dai_ops,
 };
 
+static const struct snd_soc_component_driver ep93xx_ac97_component = {
+	.name		= "ep93xx-ac97",
+};
+
 static int ep93xx_ac97_probe(struct platform_device *pdev)
 {
 	struct ep93xx_ac97_info *info;
@@ -390,7 +395,8 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
 	ep93xx_ac97_info = info;
 	platform_set_drvdata(pdev, info);
 
-	ret = snd_soc_register_dai(&pdev->dev, &ep93xx_ac97_dai);
+	ret = snd_soc_register_component(&pdev->dev, &ep93xx_ac97_component,
+					 &ep93xx_ac97_dai, 1);
 	if (ret)
 		goto fail;
 
@@ -407,7 +413,7 @@ static int ep93xx_ac97_remove(struct platform_device *pdev)
 {
 	struct ep93xx_ac97_info	*info = platform_get_drvdata(pdev);
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	/* disable the AC97 controller */
 	ep93xx_ac97_write_reg(info, AC97GCR, 0);
diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c
index 323ed69b7975..5c1102e9e159 100644
--- a/sound/soc/cirrus/ep93xx-i2s.c
+++ b/sound/soc/cirrus/ep93xx-i2s.c
@@ -30,8 +30,6 @@
 #include <mach/ep93xx-regs.h>
 #include <linux/platform_data/dma-ep93xx.h>
 
-#include "ep93xx-pcm.h"
-
 #define EP93XX_I2S_TXCLKCFG		0x00
 #define EP93XX_I2S_RXCLKCFG		0x04
 #define EP93XX_I2S_GLCTRL		0x0C
@@ -62,18 +60,20 @@ struct ep93xx_i2s_info {
 	struct clk			*mclk;
 	struct clk			*sclk;
 	struct clk			*lrclk;
-	struct ep93xx_pcm_dma_params	*dma_params;
+	struct ep93xx_dma_data		*dma_data;
 	void __iomem			*regs;
 };
 
-struct ep93xx_pcm_dma_params ep93xx_i2s_dma_params[] = {
+struct ep93xx_dma_data ep93xx_i2s_dma_data[] = {
 	[SNDRV_PCM_STREAM_PLAYBACK] = {
 		.name		= "i2s-pcm-out",
-		.dma_port	= EP93XX_DMA_I2S1,
+		.port		= EP93XX_DMA_I2S1,
+		.direction	= DMA_MEM_TO_DEV,
 	},
 	[SNDRV_PCM_STREAM_CAPTURE] = {
 		.name		= "i2s-pcm-in",
-		.dma_port	= EP93XX_DMA_I2S1,
+		.port		= EP93XX_DMA_I2S1,
+		.direction	= DMA_DEV_TO_MEM,
 	},
 };
 
@@ -147,7 +147,7 @@ static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
 	snd_soc_dai_set_dma_data(cpu_dai, substream,
-				 &info->dma_params[substream->stream]);
+				 &info->dma_data[substream->stream]);
 	return 0;
 }
 
@@ -366,6 +366,10 @@ static struct snd_soc_dai_driver ep93xx_i2s_dai = {
 	.ops		= &ep93xx_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver ep93xx_i2s_component = {
+	.name		= "ep93xx-i2s",
+};
+
 static int ep93xx_i2s_probe(struct platform_device *pdev)
 {
 	struct ep93xx_i2s_info *info;
@@ -403,9 +407,10 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
 	}
 
 	dev_set_drvdata(&pdev->dev, info);
-	info->dma_params = ep93xx_i2s_dma_params;
+	info->dma_data = ep93xx_i2s_dma_data;
 
-	err = snd_soc_register_dai(&pdev->dev, &ep93xx_i2s_dai);
+	err = snd_soc_register_component(&pdev->dev, &ep93xx_i2s_component,
+					 &ep93xx_i2s_dai, 1);
 	if (err)
 		goto fail_put_lrclk;
 
@@ -426,7 +431,7 @@ static int ep93xx_i2s_remove(struct platform_device *pdev)
 {
 	struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev);
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	dev_set_drvdata(&pdev->dev, NULL);
 	clk_put(info->lrclk);
 	clk_put(info->sclk);
diff --git a/sound/soc/cirrus/ep93xx-pcm.c b/sound/soc/cirrus/ep93xx-pcm.c
index 72eb7a49e16a..488032690378 100644
--- a/sound/soc/cirrus/ep93xx-pcm.c
+++ b/sound/soc/cirrus/ep93xx-pcm.c
@@ -29,8 +29,6 @@
 #include <mach/hardware.h>
 #include <mach/ep93xx-regs.h>
 
-#include "ep93xx-pcm.h"
-
 static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
 	.info			= (SNDRV_PCM_INFO_MMAP		|
 				   SNDRV_PCM_INFO_MMAP_VALID	|
@@ -68,40 +66,12 @@ static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param)
 static int ep93xx_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 ep93xx_pcm_dma_params *dma_params;
-	struct ep93xx_dma_data *dma_data;
-	int ret;
 
 	snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);
 
-	dma_data = kmalloc(sizeof(*dma_data), GFP_KERNEL);
-	if (!dma_data)
-		return -ENOMEM;
-
-	dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream);
-	dma_data->port = dma_params->dma_port;
-	dma_data->name = dma_params->name;
-	dma_data->direction = snd_pcm_substream_to_dma_direction(substream);
-
-	ret = snd_dmaengine_pcm_open(substream, ep93xx_pcm_dma_filter, dma_data);
-	if (ret) {
-		kfree(dma_data);
-		return ret;
-	}
-
-	snd_dmaengine_pcm_set_data(substream, dma_data);
-
-	return 0;
-}
-
-static int ep93xx_pcm_close(struct snd_pcm_substream *substream)
-{
-	struct dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
-
-	snd_dmaengine_pcm_close(substream);
-	kfree(dma_data);
-	return 0;
+	return snd_dmaengine_pcm_open_request_chan(substream,
+			ep93xx_pcm_dma_filter,
+			snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
 }
 
 static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream,
@@ -131,7 +101,7 @@ static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream,
 
 static struct snd_pcm_ops ep93xx_pcm_ops = {
 	.open		= ep93xx_pcm_open,
-	.close		= ep93xx_pcm_close,
+	.close		= snd_dmaengine_pcm_close_release_chan,
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= ep93xx_pcm_hw_params,
 	.hw_free	= ep93xx_pcm_hw_free,
diff --git a/sound/soc/cirrus/ep93xx-pcm.h b/sound/soc/cirrus/ep93xx-pcm.h
deleted file mode 100644
index 111e1121ecb8..000000000000
--- a/sound/soc/cirrus/ep93xx-pcm.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * sound/soc/ep93xx/ep93xx-pcm.h - EP93xx ALSA PCM interface
- *
- * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
- * Copyright (C) 2006 Applied Data Systems
- *
- * 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 _EP93XX_SND_SOC_PCM_H
-#define _EP93XX_SND_SOC_PCM_H
-
-struct ep93xx_pcm_dma_params {
-	char	*name;
-	int	dma_port;
-};
-
-#endif /* _EP93XX_SND_SOC_PCM_H */
diff --git a/sound/soc/cirrus/simone.c b/sound/soc/cirrus/simone.c
index a397bb0d8179..4d094d00c34a 100644
--- a/sound/soc/cirrus/simone.c
+++ b/sound/soc/cirrus/simone.c
@@ -21,8 +21,6 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 
-#include "ep93xx-pcm.h"
-
 static struct snd_soc_dai_link simone_dai = {
 	.name		= "AC97",
 	.stream_name	= "AC97 HiFi",
diff --git a/sound/soc/cirrus/snappercl15.c b/sound/soc/cirrus/snappercl15.c
index 9d77fe28dfcc..69041074f2c1 100644
--- a/sound/soc/cirrus/snappercl15.c
+++ b/sound/soc/cirrus/snappercl15.c
@@ -21,7 +21,6 @@
 #include <mach/hardware.h>
 
 #include "../codecs/tlv320aic23.h"
-#include "ep93xx-pcm.h"
 
 #define CODEC_CLOCK 5644800
 
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 45b72561c615..2f45f00e31b0 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -26,6 +26,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_AK4641 if I2C
 	select SND_SOC_AK4642 if I2C
 	select SND_SOC_AK4671 if I2C
+	select SND_SOC_AK5386
 	select SND_SOC_ALC5623 if I2C
 	select SND_SOC_ALC5632 if I2C
 	select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
@@ -63,6 +64,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_STA32X if I2C
 	select SND_SOC_STA529 if I2C
 	select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
+	select SND_SOC_TAS5086 if I2C
 	select SND_SOC_TLV320AIC23 if I2C
 	select SND_SOC_TLV320AIC26 if SPI_MASTER
 	select SND_SOC_TLV320AIC32X4 if I2C
@@ -203,6 +205,9 @@ config SND_SOC_AK4642
 config SND_SOC_AK4671
 	tristate
 
+config SND_SOC_AK5386
+	tristate
+
 config SND_SOC_ALC5623
        tristate
 config SND_SOC_ALC5632
@@ -320,11 +325,14 @@ config SND_SOC_STA529
 config SND_SOC_STAC9766
 	tristate
 
+config SND_SOC_TAS5086
+	tristate
+
 config SND_SOC_TLV320AIC23
 	tristate
 
 config SND_SOC_TLV320AIC26
-	tristate "TI TLV320AIC26 Codec support" if SND_SOC_OF_SIMPLE
+	tristate
 	depends on SPI
 
 config SND_SOC_TLV320AIC32X4
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 6a3b3c3b8b41..b9e41c9a1f4c 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -14,6 +14,7 @@ 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-ak5386-objs := ak5386.o
 snd-soc-arizona-objs := arizona.o
 snd-soc-cq93vc-objs := cq93vc.o
 snd-soc-cs42l51-objs := cs42l51.o
@@ -55,6 +56,7 @@ snd-soc-ssm2602-objs := ssm2602.o
 snd-soc-sta32x-objs := sta32x.o
 snd-soc-sta529-objs := sta529.o
 snd-soc-stac9766-objs := stac9766.o
+snd-soc-tas5086-objs := tas5086.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
@@ -137,6 +139,7 @@ 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_AK5386)	+= snd-soc-ak5386.o
 obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
 obj-$(CONFIG_SND_SOC_ALC5632)	+= snd-soc-alc5632.o
 obj-$(CONFIG_SND_SOC_ARIZONA)	+= snd-soc-arizona.o
@@ -177,6 +180,7 @@ obj-$(CONFIG_SND_SOC_SSM2602)	+= snd-soc-ssm2602.o
 obj-$(CONFIG_SND_SOC_STA32X)   += snd-soc-sta32x.o
 obj-$(CONFIG_SND_SOC_STA529)   += snd-soc-sta529.o
 obj-$(CONFIG_SND_SOC_STAC9766)	+= snd-soc-stac9766.o
+obj-$(CONFIG_SND_SOC_TAS5086)	+= snd-soc-tas5086.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)	+= snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)	+= snd-soc-tlv320aic26.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3X)	+= snd-soc-tlv320aic3x.o
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index 068b3ae56a17..1aa10ddf3a61 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -133,6 +133,8 @@ struct adau1373 {
 #define ADAU1373_DAI_FORMAT_DSP		0x3
 
 #define ADAU1373_BCLKDIV_SOURCE		BIT(5)
+#define ADAU1373_BCLKDIV_SR_MASK	(0x07 << 2)
+#define ADAU1373_BCLKDIV_BCLK_MASK	0x03
 #define ADAU1373_BCLKDIV_32		0x03
 #define ADAU1373_BCLKDIV_64		0x02
 #define ADAU1373_BCLKDIV_128		0x01
@@ -937,7 +939,8 @@ static int adau1373_hw_params(struct snd_pcm_substream *substream,
 	adau1373_dai->enable_src = (div != 0);
 
 	snd_soc_update_bits(codec, ADAU1373_BCLKDIV(dai->id),
-		~ADAU1373_BCLKDIV_SOURCE, (div << 2) | ADAU1373_BCLKDIV_64);
+		ADAU1373_BCLKDIV_SR_MASK | ADAU1373_BCLKDIV_BCLK_MASK,
+		(div << 2) | ADAU1373_BCLKDIV_64);
 
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S16_LE:
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index 6f6c335a5baa..c7cfdf957e4d 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -55,6 +55,7 @@ static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			      unsigned int format)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
+	struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
 	int val = 0;
 	int ret;
 
@@ -77,9 +78,9 @@ static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
 		return -EINVAL;
 
-	ret = snd_soc_update_bits(codec, AK4104_REG_CONTROL1,
-				  AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1,
-				  val);
+	ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
+				 AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1,
+				 val);
 	if (ret < 0)
 		return ret;
 
@@ -91,11 +92,12 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_soc_dai *dai)
 {
 	struct snd_soc_codec *codec = dai->codec;
-	int val = 0;
+	struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
+	int ret, val = 0;
 
 	/* set the IEC958 bits: consumer mode, no copyright bit */
 	val |= IEC958_AES0_CON_NOT_COPYRIGHT;
-	snd_soc_write(codec, AK4104_REG_CHN_STATUS(0), val);
+	regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(0), val);
 
 	val = 0;
 
@@ -132,11 +134,33 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	return snd_soc_write(codec, AK4104_REG_CHN_STATUS(3), val);
+	ret = regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(3), val);
+	if (ret < 0)
+		return ret;
+
+	/* enable transmitter */
+	ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
+				 AK4104_TX_TXE, AK4104_TX_TXE);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int ak4104_hw_free(struct snd_pcm_substream *substream,
+			  struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
+
+	/* disable transmitter */
+	return regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
+				  AK4104_TX_TXE, 0);
 }
 
 static const struct snd_soc_dai_ops ak4101_dai_ops = {
 	.hw_params = ak4104_hw_params,
+	.hw_free = ak4104_hw_free,
 	.set_fmt = ak4104_set_dai_fmt,
 };
 
@@ -160,20 +184,17 @@ static int ak4104_probe(struct snd_soc_codec *codec)
 	int ret;
 
 	codec->control_data = ak4104->regmap;
-	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-	if (ret != 0)
-		return ret;
 
 	/* set power-up and non-reset bits */
-	ret = snd_soc_update_bits(codec, AK4104_REG_CONTROL1,
-				  AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN,
-				  AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
+	ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
+				 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN,
+				 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
 	if (ret < 0)
 		return ret;
 
 	/* enable transmitter */
-	ret = snd_soc_update_bits(codec, AK4104_REG_TX,
-				  AK4104_TX_TXE, AK4104_TX_TXE);
+	ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
+				 AK4104_TX_TXE, AK4104_TX_TXE);
 	if (ret < 0)
 		return ret;
 
@@ -182,8 +203,10 @@ static int ak4104_probe(struct snd_soc_codec *codec)
 
 static int ak4104_remove(struct snd_soc_codec *codec)
 {
-	snd_soc_update_bits(codec, AK4104_REG_CONTROL1,
-			    AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0);
+	struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
+
+	regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
+			   AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0);
 
 	return 0;
 }
diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c
new file mode 100644
index 000000000000..1f303983ae02
--- /dev/null
+++ b/sound/soc/codecs/ak5386.c
@@ -0,0 +1,152 @@
+/*
+ * ALSA SoC driver for
+ *    Asahi Kasei AK5386 Single-ended 24-Bit 192kHz delta-sigma ADC
+ *
+ * (c) 2013 Daniel Mack <zonque@gmail.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/slab.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+
+struct ak5386_priv {
+	int reset_gpio;
+};
+
+static struct snd_soc_codec_driver soc_codec_ak5386;
+
+static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int format)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+
+	format &= SND_SOC_DAIFMT_FORMAT_MASK;
+	if (format != SND_SOC_DAIFMT_LEFT_J &&
+	    format != SND_SOC_DAIFMT_I2S) {
+		dev_err(codec->dev, "Invalid DAI format\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ak5386_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 ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	/*
+	 * From the datasheet:
+	 *
+	 * All external clocks (MCLK, SCLK and LRCK) must be present unless
+	 * PDN pin = “L”. If these clocks are not provided, the AK5386 may
+	 * draw excess current due to its use of internal dynamically
+	 * refreshed logic. If the external clocks are not present, place
+	 * the AK5386 in power-down mode (PDN pin = “L”).
+	 */
+
+	if (gpio_is_valid(priv->reset_gpio))
+		gpio_set_value(priv->reset_gpio, 1);
+
+	return 0;
+}
+
+static int ak5386_hw_free(struct snd_pcm_substream *substream,
+			  struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	if (gpio_is_valid(priv->reset_gpio))
+		gpio_set_value(priv->reset_gpio, 0);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops ak5386_dai_ops = {
+	.set_fmt	= ak5386_set_dai_fmt,
+	.hw_params	= ak5386_hw_params,
+	.hw_free	= ak5386_hw_free,
+};
+
+static struct snd_soc_dai_driver ak5386_dai = {
+	.name		= "ak5386-hifi",
+	.capture	= {
+		.stream_name	= "Capture",
+		.channels_min	= 1,
+		.channels_max	= 2,
+		.rates		= SNDRV_PCM_RATE_8000_192000,
+		.formats	= SNDRV_PCM_FMTBIT_S8     |
+				  SNDRV_PCM_FMTBIT_S16_LE |
+				  SNDRV_PCM_FMTBIT_S24_LE |
+				  SNDRV_PCM_FMTBIT_S24_3LE,
+	},
+	.ops	= &ak5386_dai_ops,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id ak5386_dt_ids[] = {
+	{ .compatible = "asahi-kasei,ak5386", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ak5386_dt_ids);
+#endif
+
+static int ak5386_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct ak5386_priv *priv;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->reset_gpio = -EINVAL;
+	dev_set_drvdata(dev, priv);
+
+	if (of_match_device(of_match_ptr(ak5386_dt_ids), dev))
+		priv->reset_gpio = of_get_named_gpio(dev->of_node,
+						      "reset-gpio", 0);
+
+	if (gpio_is_valid(priv->reset_gpio))
+		if (devm_gpio_request_one(dev, priv->reset_gpio,
+					  GPIOF_OUT_INIT_LOW,
+					  "AK5386 Reset"))
+			priv->reset_gpio = -EINVAL;
+
+	return snd_soc_register_codec(dev, &soc_codec_ak5386,
+				      &ak5386_dai, 1);
+}
+
+static int ak5386_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_codec(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver ak5386_driver = {
+	.probe		= ak5386_probe,
+	.remove		= ak5386_remove,
+	.driver		= {
+		.name	= "ak5386",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(ak5386_dt_ids),
+	},
+};
+
+module_platform_driver(ak5386_driver);
+
+MODULE_DESCRIPTION("ASoC driver for AK5386 ADC");
+MODULE_AUTHOR("Daniel Mack <zonque@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index e7d34711412c..389f23253831 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -10,6 +10,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/delay.h>
 #include <linux/gcd.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
@@ -65,6 +66,163 @@
 #define arizona_aif_dbg(_dai, fmt, ...) \
 	dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
 
+static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *kcontrol,
+			  int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	bool manual_ena = false;
+	int val;
+
+	switch (arizona->type) {
+	case WM5102:
+		switch (arizona->rev) {
+		case 0:
+			break;
+		default:
+			manual_ena = true;
+			break;
+		}
+	default:
+		break;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (!priv->spk_ena && manual_ena) {
+			snd_soc_write(codec, 0x4f5, 0x25a);
+			priv->spk_ena_pending = true;
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3);
+		if (val & ARIZONA_SPK_SHUTDOWN_STS) {
+			dev_crit(arizona->dev,
+				 "Speaker not enabled due to temperature\n");
+			return -EBUSY;
+		}
+
+		snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1,
+				    1 << w->shift, 1 << w->shift);
+
+		if (priv->spk_ena_pending) {
+			msleep(75);
+			snd_soc_write(codec, 0x4f5, 0xda);
+			priv->spk_ena_pending = false;
+			priv->spk_ena++;
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		if (manual_ena) {
+			priv->spk_ena--;
+			if (!priv->spk_ena)
+				snd_soc_write(codec, 0x4f5, 0x25a);
+		}
+
+		snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1,
+				    1 << w->shift, 0);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (manual_ena) {
+			if (!priv->spk_ena)
+				snd_soc_write(codec, 0x4f5, 0x0da);
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static irqreturn_t arizona_thermal_warn(int irq, void *data)
+{
+	struct arizona *arizona = data;
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
+			  &val);
+	if (ret != 0) {
+		dev_err(arizona->dev, "Failed to read thermal status: %d\n",
+			ret);
+	} else if (val & ARIZONA_SPK_SHUTDOWN_WARN_STS) {
+		dev_crit(arizona->dev, "Thermal warning\n");
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t arizona_thermal_shutdown(int irq, void *data)
+{
+	struct arizona *arizona = data;
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
+			  &val);
+	if (ret != 0) {
+		dev_err(arizona->dev, "Failed to read thermal status: %d\n",
+			ret);
+	} else if (val & ARIZONA_SPK_SHUTDOWN_STS) {
+		dev_crit(arizona->dev, "Thermal shutdown\n");
+		ret = regmap_update_bits(arizona->regmap,
+					 ARIZONA_OUTPUT_ENABLES_1,
+					 ARIZONA_OUT4L_ENA |
+					 ARIZONA_OUT4R_ENA, 0);
+		if (ret != 0)
+			dev_crit(arizona->dev,
+				 "Failed to disable speaker outputs: %d\n",
+				 ret);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static const struct snd_soc_dapm_widget arizona_spkl =
+	SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM,
+			   ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
+
+static const struct snd_soc_dapm_widget arizona_spkr =
+	SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,
+			   ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
+
+int arizona_init_spk(struct snd_soc_codec *codec)
+{
+	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct arizona *arizona = priv->arizona;
+	int ret;
+
+	ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1);
+	if (ret != 0)
+		return ret;
+
+	ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkr, 1);
+	if (ret != 0)
+		return ret;
+
+	ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN_WARN,
+				  "Thermal warning", arizona_thermal_warn,
+				  arizona);
+	if (ret != 0)
+		dev_err(arizona->dev,
+			"Failed to get thermal warning IRQ: %d\n",
+			ret);
+
+	ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN,
+				  "Thermal shutdown", arizona_thermal_shutdown,
+				  arizona);
+	if (ret != 0)
+		dev_err(arizona->dev,
+			"Failed to get thermal shutdown IRQ: %d\n",
+			ret);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_init_spk);
+
 const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
 	"None",
 	"Tone Generator 1",
@@ -274,6 +432,33 @@ EXPORT_SYMBOL_GPL(arizona_mixer_values);
 const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
 EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
 
+const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
+	"SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
+};
+EXPORT_SYMBOL_GPL(arizona_rate_text);
+
+const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
+	0, 1, 2, 8,
+};
+EXPORT_SYMBOL_GPL(arizona_rate_val);
+
+
+const struct soc_enum arizona_isrc_fsl[] = {
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
+			      ARIZONA_ISRC1_FSL_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE,
+			      arizona_rate_text, arizona_rate_val),
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
+			      ARIZONA_ISRC2_FSL_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE,
+			      arizona_rate_text, arizona_rate_val),
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
+			      ARIZONA_ISRC3_FSL_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE,
+			      arizona_rate_text, arizona_rate_val),
+};
+EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
+
 static const char *arizona_vol_ramp_text[] = {
 	"0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
 	"15ms/6dB", "30ms/6dB",
@@ -332,9 +517,27 @@ const struct soc_enum arizona_ng_hold =
 			4, arizona_ng_hold_text);
 EXPORT_SYMBOL_GPL(arizona_ng_hold);
 
+static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
+{
+	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	unsigned int val;
+	int i;
+
+	if (ena)
+		val = ARIZONA_IN_VU;
+	else
+		val = 0;
+
+	for (i = 0; i < priv->num_inputs; i++)
+		snd_soc_update_bits(codec,
+				    ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
+				    ARIZONA_IN_VU, val);
+}
+
 int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
 		  int event)
 {
+	struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
 	unsigned int reg;
 
 	if (w->shift % 2)
@@ -343,13 +546,29 @@ int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
 		reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
 
 	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		priv->in_pending++;
+		break;
 	case SND_SOC_DAPM_POST_PMU:
 		snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
+
+		/* If this is the last input pending then allow VU */
+		priv->in_pending--;
+		if (priv->in_pending == 0) {
+			msleep(1);
+			arizona_in_set_vu(w->codec, 1);
+		}
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE,
-				    ARIZONA_IN1L_MUTE);
+		snd_soc_update_bits(w->codec, reg,
+				    ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
+				    ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
 		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* Disable volume updates if no inputs are enabled */
+		reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES);
+		if (reg == 0)
+			arizona_in_set_vu(w->codec, 0);
 	}
 
 	return 0;
@@ -360,6 +579,24 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
 		   struct snd_kcontrol *kcontrol,
 		   int event)
 {
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		switch (w->shift) {
+		case ARIZONA_OUT1L_ENA_SHIFT:
+		case ARIZONA_OUT1R_ENA_SHIFT:
+		case ARIZONA_OUT2L_ENA_SHIFT:
+		case ARIZONA_OUT2R_ENA_SHIFT:
+		case ARIZONA_OUT3L_ENA_SHIFT:
+		case ARIZONA_OUT3R_ENA_SHIFT:
+			msleep(17);
+			break;
+
+		default:
+			break;
+		}
+		break;
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(arizona_out_ev);
@@ -502,27 +739,27 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 		break;
 	case 11289600:
 	case 12288000:
-		val |= 1 << ARIZONA_SYSCLK_FREQ_SHIFT;
+		val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
 		break;
 	case 22579200:
 	case 24576000:
-		val |= 2 << ARIZONA_SYSCLK_FREQ_SHIFT;
+		val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
 		break;
 	case 45158400:
 	case 49152000:
-		val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT;
+		val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
 		break;
 	case 67737600:
 	case 73728000:
-		val |= 4 << ARIZONA_SYSCLK_FREQ_SHIFT;
+		val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
 		break;
 	case 90316800:
 	case 98304000:
-		val |= 5 << ARIZONA_SYSCLK_FREQ_SHIFT;
+		val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
 		break;
 	case 135475200:
 	case 147456000:
-		val |= 6 << ARIZONA_SYSCLK_FREQ_SHIFT;
+		val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
 		break;
 	case 0:
 		dev_dbg(arizona->dev, "%s cleared\n", name);
@@ -816,7 +1053,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
 	struct arizona *arizona = priv->arizona;
 	int base = dai->driver->base;
 	const int *rates;
-	int i, ret;
+	int i, ret, val;
 	int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
 	int bclk, lrclk, wl, frame, bclk_target;
 
@@ -832,6 +1069,13 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
 		bclk_target *= chan_limit;
 	}
 
+	/* Force stereo for I2S mode */
+	val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
+	if (params_channels(params) == 1 && (val & ARIZONA_AIF1_FMT_MASK)) {
+		arizona_aif_dbg(dai, "Forcing stereo mode\n");
+		bclk_target *= 2;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
 		if (rates[i] >= bclk_target &&
 		    rates[i] % params_rate(params) == 0) {
@@ -988,6 +1232,16 @@ static struct {
 	{ 1000000, 13500000, 0,  1 },
 };
 
+static struct {
+	unsigned int min;
+	unsigned int max;
+	u16 gain;
+} fll_gains[] = {
+	{       0,   256000, 0 },
+	{  256000,  1000000, 2 },
+	{ 1000000, 13500000, 4 },
+};
+
 struct arizona_fll_cfg {
 	int n;
 	int theta;
@@ -995,6 +1249,7 @@ struct arizona_fll_cfg {
 	int refdiv;
 	int outdiv;
 	int fratio;
+	int gain;
 };
 
 static int arizona_calc_fll(struct arizona_fll *fll,
@@ -1054,6 +1309,18 @@ static int arizona_calc_fll(struct arizona_fll *fll,
 		return -EINVAL;
 	}
 
+	for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
+		if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
+			cfg->gain = fll_gains[i].gain;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(fll_gains)) {
+		arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
+				Fref);
+		return -EINVAL;
+	}
+
 	cfg->n = target / (ratio * Fref);
 
 	if (target % (ratio * Fref)) {
@@ -1081,13 +1348,15 @@ static int arizona_calc_fll(struct arizona_fll *fll,
 			cfg->n, cfg->theta, cfg->lambda);
 	arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
 			cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
+	arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
 
 	return 0;
 
 }
 
 static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
-			      struct arizona_fll_cfg *cfg, int source)
+			      struct arizona_fll_cfg *cfg, int source,
+			      bool sync)
 {
 	regmap_update_bits(arizona->regmap, base + 3,
 			   ARIZONA_FLL1_THETA_MASK, cfg->theta);
@@ -1102,87 +1371,84 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
 			   cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
 			   source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
 
+	if (sync)
+		regmap_update_bits(arizona->regmap, base + 0x7,
+				   ARIZONA_FLL1_GAIN_MASK,
+				   cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
+	else
+		regmap_update_bits(arizona->regmap, base + 0x9,
+				   ARIZONA_FLL1_GAIN_MASK,
+				   cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
+
 	regmap_update_bits(arizona->regmap, base + 2,
 			   ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
 			   ARIZONA_FLL1_CTRL_UPD | cfg->n);
 }
 
-int arizona_set_fll(struct arizona_fll *fll, int source,
-		    unsigned int Fref, unsigned int Fout)
+static bool arizona_is_enabled_fll(struct arizona_fll *fll)
 {
 	struct arizona *arizona = fll->arizona;
-	struct arizona_fll_cfg cfg, sync;
-	unsigned int reg, val;
-	int syncsrc;
-	bool ena;
+	unsigned int reg;
 	int ret;
 
-	if (fll->fref == Fref && fll->fout == Fout)
-		return 0;
-
 	ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
 	if (ret != 0) {
 		arizona_fll_err(fll, "Failed to read current state: %d\n",
 				ret);
 		return ret;
 	}
-	ena = reg & ARIZONA_FLL1_ENA;
 
-	if (Fout) {
-		/* Do we have a 32kHz reference? */
-		regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
-		switch (val & ARIZONA_CLK_32K_SRC_MASK) {
-		case ARIZONA_CLK_SRC_MCLK1:
-		case ARIZONA_CLK_SRC_MCLK2:
-			syncsrc = val & ARIZONA_CLK_32K_SRC_MASK;
-			break;
-		default:
-			syncsrc = -1;
-		}
+	return reg & ARIZONA_FLL1_ENA;
+}
 
-		if (source == syncsrc)
-			syncsrc = -1;
+static void arizona_enable_fll(struct arizona_fll *fll,
+			      struct arizona_fll_cfg *ref,
+			      struct arizona_fll_cfg *sync)
+{
+	struct arizona *arizona = fll->arizona;
+	int ret;
 
-		if (syncsrc >= 0) {
-			ret = arizona_calc_fll(fll, &sync, Fref, Fout);
-			if (ret != 0)
-				return ret;
+	/*
+	 * If we have both REFCLK and SYNCCLK then enable both,
+	 * otherwise apply the SYNCCLK settings to REFCLK.
+	 */
+	if (fll->ref_src >= 0 && fll->ref_src != fll->sync_src) {
+		regmap_update_bits(arizona->regmap, fll->base + 5,
+				   ARIZONA_FLL1_OUTDIV_MASK,
+				   ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
+
+		arizona_apply_fll(arizona, fll->base, ref, fll->ref_src,
+				  false);
+		if (fll->sync_src >= 0)
+			arizona_apply_fll(arizona, fll->base + 0x10, sync,
+					  fll->sync_src, true);
+	} else if (fll->sync_src >= 0) {
+		regmap_update_bits(arizona->regmap, fll->base + 5,
+				   ARIZONA_FLL1_OUTDIV_MASK,
+				   sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
+
+		arizona_apply_fll(arizona, fll->base, sync,
+				  fll->sync_src, false);
 
-			ret = arizona_calc_fll(fll, &cfg, 32768, Fout);
-			if (ret != 0)
-				return ret;
-		} else {
-			ret = arizona_calc_fll(fll, &cfg, Fref, Fout);
-			if (ret != 0)
-				return ret;
-		}
-	} else {
-		regmap_update_bits(arizona->regmap, fll->base + 1,
-				   ARIZONA_FLL1_ENA, 0);
 		regmap_update_bits(arizona->regmap, fll->base + 0x11,
 				   ARIZONA_FLL1_SYNC_ENA, 0);
-
-		if (ena)
-			pm_runtime_put_autosuspend(arizona->dev);
-
-		fll->fref = Fref;
-		fll->fout = Fout;
-
-		return 0;
-	}
-
-	regmap_update_bits(arizona->regmap, fll->base + 5,
-			   ARIZONA_FLL1_OUTDIV_MASK,
-			   cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
-
-	if (syncsrc >= 0) {
-		arizona_apply_fll(arizona, fll->base, &cfg, syncsrc);
-		arizona_apply_fll(arizona, fll->base + 0x10, &sync, source);
 	} else {
-		arizona_apply_fll(arizona, fll->base, &cfg, source);
+		arizona_fll_err(fll, "No clocks provided\n");
+		return;
 	}
 
-	if (!ena)
+	/*
+	 * Increase the bandwidth if we're not using a low frequency
+	 * sync source.
+	 */
+	if (fll->sync_src >= 0 && fll->sync_freq > 100000)
+		regmap_update_bits(arizona->regmap, fll->base + 0x17,
+				   ARIZONA_FLL1_SYNC_BW, 0);
+	else
+		regmap_update_bits(arizona->regmap, fll->base + 0x17,
+				   ARIZONA_FLL1_SYNC_BW, ARIZONA_FLL1_SYNC_BW);
+
+	if (!arizona_is_enabled_fll(fll))
 		pm_runtime_get(arizona->dev);
 
 	/* Clear any pending completions */
@@ -1190,7 +1456,8 @@ int arizona_set_fll(struct arizona_fll *fll, int source,
 
 	regmap_update_bits(arizona->regmap, fll->base + 1,
 			   ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
-	if (syncsrc >= 0)
+	if (fll->ref_src >= 0 && fll->sync_src >= 0 &&
+	    fll->ref_src != fll->sync_src)
 		regmap_update_bits(arizona->regmap, fll->base + 0x11,
 				   ARIZONA_FLL1_SYNC_ENA,
 				   ARIZONA_FLL1_SYNC_ENA);
@@ -1199,10 +1466,88 @@ int arizona_set_fll(struct arizona_fll *fll, int source,
 					  msecs_to_jiffies(250));
 	if (ret == 0)
 		arizona_fll_warn(fll, "Timed out waiting for lock\n");
+}
+
+static void arizona_disable_fll(struct arizona_fll *fll)
+{
+	struct arizona *arizona = fll->arizona;
+	bool change;
+
+	regmap_update_bits_check(arizona->regmap, fll->base + 1,
+				 ARIZONA_FLL1_ENA, 0, &change);
+	regmap_update_bits(arizona->regmap, fll->base + 0x11,
+			   ARIZONA_FLL1_SYNC_ENA, 0);
+
+	if (change)
+		pm_runtime_put_autosuspend(arizona->dev);
+}
+
+int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
+			   unsigned int Fref, unsigned int Fout)
+{
+	struct arizona_fll_cfg ref, sync;
+	int ret;
 
-	fll->fref = Fref;
+	if (fll->ref_src == source && fll->ref_freq == Fref)
+		return 0;
+
+	if (fll->fout && Fref > 0) {
+		ret = arizona_calc_fll(fll, &ref, Fref, fll->fout);
+		if (ret != 0)
+			return ret;
+
+		if (fll->sync_src >= 0) {
+			ret = arizona_calc_fll(fll, &sync, fll->sync_freq,
+					       fll->fout);
+			if (ret != 0)
+				return ret;
+		}
+	}
+
+	fll->ref_src = source;
+	fll->ref_freq = Fref;
+
+	if (fll->fout && Fref > 0) {
+		arizona_enable_fll(fll, &ref, &sync);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
+
+int arizona_set_fll(struct arizona_fll *fll, int source,
+		    unsigned int Fref, unsigned int Fout)
+{
+	struct arizona_fll_cfg ref, sync;
+	int ret;
+
+	if (fll->sync_src == source &&
+	    fll->sync_freq == Fref && fll->fout == Fout)
+		return 0;
+
+	if (Fout) {
+		if (fll->ref_src >= 0) {
+			ret = arizona_calc_fll(fll, &ref, fll->ref_freq,
+					       Fout);
+			if (ret != 0)
+				return ret;
+		}
+
+		ret = arizona_calc_fll(fll, &sync, Fref, Fout);
+		if (ret != 0)
+			return ret;
+	}
+
+	fll->sync_src = source;
+	fll->sync_freq = Fref;
 	fll->fout = Fout;
 
+	if (Fout) {
+		arizona_enable_fll(fll, &ref, &sync);
+	} else {
+		arizona_disable_fll(fll);
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(arizona_set_fll);
@@ -1211,12 +1556,26 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
 		     int ok_irq, struct arizona_fll *fll)
 {
 	int ret;
+	unsigned int val;
 
 	init_completion(&fll->ok);
 
 	fll->id = id;
 	fll->base = base;
 	fll->arizona = arizona;
+	fll->sync_src = ARIZONA_FLL_SRC_NONE;
+
+	/* Configure default refclk to 32kHz if we have one */
+	regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
+	switch (val & ARIZONA_CLK_32K_SRC_MASK) {
+	case ARIZONA_CLK_SRC_MCLK1:
+	case ARIZONA_CLK_SRC_MCLK2:
+		fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
+		break;
+	default:
+		fll->ref_src = ARIZONA_FLL_SRC_NONE;
+	}
+	fll->ref_freq = 32768;
 
 	snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
 	snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index 13dd2916b721..af39f1006427 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -32,6 +32,7 @@
 #define ARIZONA_CLK_SRC_AIF2BCLK 0x9
 #define ARIZONA_CLK_SRC_AIF3BCLK 0xa
 
+#define ARIZONA_FLL_SRC_NONE      -1
 #define ARIZONA_FLL_SRC_MCLK1      0
 #define ARIZONA_FLL_SRC_MCLK2      1
 #define ARIZONA_FLL_SRC_SLIMCLK    3
@@ -48,6 +49,14 @@
 #define ARIZONA_MIXER_VOL_SHIFT                 1
 #define ARIZONA_MIXER_VOL_WIDTH                 7
 
+#define ARIZONA_CLK_6MHZ   0
+#define ARIZONA_CLK_12MHZ  1
+#define ARIZONA_CLK_24MHZ  2
+#define ARIZONA_CLK_49MHZ  3
+#define ARIZONA_CLK_73MHZ  4
+#define ARIZONA_CLK_98MHZ  5
+#define ARIZONA_CLK_147MHZ 6
+
 #define ARIZONA_MAX_DAI  4
 #define ARIZONA_MAX_ADSP 4
 
@@ -64,6 +73,12 @@ struct arizona_priv {
 	int sysclk;
 	int asyncclk;
 	struct arizona_dai_priv dai[ARIZONA_MAX_DAI];
+
+	int num_inputs;
+	unsigned int in_pending;
+
+	unsigned int spk_ena:2;
+	unsigned int spk_ena_pending:1;
 };
 
 #define ARIZONA_NUM_MIXER_INPUTS 99
@@ -165,6 +180,12 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
 	ARIZONA_MIXER_ROUTES(name, name "L"), \
 	ARIZONA_MIXER_ROUTES(name, name "R")
 
+#define ARIZONA_RATE_ENUM_SIZE 4
+extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];
+extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE];
+
+extern const struct soc_enum arizona_isrc_fsl[];
+
 extern const struct soc_enum arizona_in_vi_ramp;
 extern const struct soc_enum arizona_in_vd_ramp;
 
@@ -201,8 +222,12 @@ struct arizona_fll {
 	unsigned int base;
 	unsigned int vco_mult;
 	struct completion ok;
-	unsigned int fref;
+
 	unsigned int fout;
+	int sync_src;
+	unsigned int sync_freq;
+	int ref_src;
+	unsigned int ref_freq;
 
 	char lock_name[ARIZONA_FLL_NAME_LEN];
 	char clock_ok_name[ARIZONA_FLL_NAME_LEN];
@@ -210,9 +235,13 @@ struct arizona_fll {
 
 extern int arizona_init_fll(struct arizona *arizona, int id, int base,
 			    int lock_irq, int ok_irq, struct arizona_fll *fll);
+extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
+				  unsigned int Fref, unsigned int Fout);
 extern int arizona_set_fll(struct arizona_fll *fll, int source,
 			   unsigned int Fref, unsigned int Fout);
 
+extern int arizona_init_spk(struct snd_soc_codec *codec);
+
 extern int arizona_init_dai(struct arizona_priv *priv, int dai);
 
 int arizona_set_output_mode(struct snd_soc_codec *codec, int output,
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index 2415a4118dbd..03036b326732 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -39,17 +39,15 @@
 
 /*
  * CS4271 registers
- * High byte represents SPI chip address (0x10) + write command (0)
- * Low byte - codec register address
  */
-#define CS4271_MODE1	0x2001	/* Mode Control 1 */
-#define CS4271_DACCTL	0x2002	/* DAC Control */
-#define CS4271_DACVOL	0x2003	/* DAC Volume & Mixing Control */
-#define CS4271_VOLA	0x2004	/* DAC Channel A Volume Control */
-#define CS4271_VOLB	0x2005	/* DAC Channel B Volume Control */
-#define CS4271_ADCCTL	0x2006	/* ADC Control */
-#define CS4271_MODE2	0x2007	/* Mode Control 2 */
-#define CS4271_CHIPID	0x2008	/* Chip ID */
+#define CS4271_MODE1	0x01	/* Mode Control 1 */
+#define CS4271_DACCTL	0x02	/* DAC Control */
+#define CS4271_DACVOL	0x03	/* DAC Volume & Mixing Control */
+#define CS4271_VOLA	0x04	/* DAC Channel A Volume Control */
+#define CS4271_VOLB	0x05	/* DAC Channel B Volume Control */
+#define CS4271_ADCCTL	0x06	/* ADC Control */
+#define CS4271_MODE2	0x07	/* Mode Control 2 */
+#define CS4271_CHIPID	0x08	/* Chip ID */
 
 #define CS4271_FIRSTREG	CS4271_MODE1
 #define CS4271_LASTREG	CS4271_MODE2
@@ -144,23 +142,27 @@
  * Array do not include Chip ID, as codec driver does not use
  * registers read operations at all
  */
-static const u8 cs4271_dflt_reg[CS4271_NR_REGS] = {
-	0,
-	0,
-	CS4271_DACCTL_AMUTE,
-	CS4271_DACVOL_SOFT | CS4271_DACVOL_ATAPI_AL_BR,
-	0,
-	0,
-	0,
-	0,
+static const struct reg_default cs4271_reg_defaults[] = {
+	{ CS4271_MODE1,		0, },
+	{ CS4271_DACCTL,	CS4271_DACCTL_AMUTE, },
+	{ CS4271_DACVOL,	CS4271_DACVOL_SOFT | CS4271_DACVOL_ATAPI_AL_BR, },
+	{ CS4271_VOLA,		0, },
+	{ CS4271_VOLB,		0, },
+	{ CS4271_ADCCTL,	0, },
+	{ CS4271_MODE2,		0, },
 };
 
+static bool cs4271_volatile_reg(struct device *dev, unsigned int reg)
+{
+	return reg == CS4271_CHIPID;
+}
+
 struct cs4271_private {
 	/* SND_SOC_I2C or SND_SOC_SPI */
-	enum snd_soc_control_type	bus_type;
 	unsigned int			mclk;
 	bool				master;
 	bool				deemph;
+	struct regmap			*regmap;
 	/* Current sample rate for de-emphasis control */
 	int				rate;
 	/* GPIO driving Reset pin, if any */
@@ -210,14 +212,14 @@ static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_LEFT_J:
 		val |= CS4271_MODE1_DAC_DIF_LJ;
-		ret = snd_soc_update_bits(codec, CS4271_ADCCTL,
+		ret = regmap_update_bits(cs4271->regmap, CS4271_ADCCTL,
 			CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_LJ);
 		if (ret < 0)
 			return ret;
 		break;
 	case SND_SOC_DAIFMT_I2S:
 		val |= CS4271_MODE1_DAC_DIF_I2S;
-		ret = snd_soc_update_bits(codec, CS4271_ADCCTL,
+		ret = regmap_update_bits(cs4271->regmap, CS4271_ADCCTL,
 			CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_I2S);
 		if (ret < 0)
 			return ret;
@@ -227,7 +229,7 @@ static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	ret = snd_soc_update_bits(codec, CS4271_MODE1,
+	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE1,
 		CS4271_MODE1_DAC_DIF_MASK | CS4271_MODE1_MASTER, val);
 	if (ret < 0)
 		return ret;
@@ -252,7 +254,7 @@ static int cs4271_set_deemph(struct snd_soc_codec *codec)
 		val <<= 4;
 	}
 
-	ret = snd_soc_update_bits(codec, CS4271_DACCTL,
+	ret = regmap_update_bits(cs4271->regmap, CS4271_DACCTL,
 		CS4271_DACCTL_DEM_MASK, val);
 	if (ret < 0)
 		return ret;
@@ -341,14 +343,14 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream,
 		     !dai->capture_active) ||
 		    (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
 		     !dai->playback_active)) {
-			ret = snd_soc_update_bits(codec, CS4271_MODE2,
-						  CS4271_MODE2_PDN,
-						  CS4271_MODE2_PDN);
+			ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
+						 CS4271_MODE2_PDN,
+						 CS4271_MODE2_PDN);
 			if (ret < 0)
 				return ret;
 
-			ret = snd_soc_update_bits(codec, CS4271_MODE2,
-						  CS4271_MODE2_PDN, 0);
+			ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
+						 CS4271_MODE2_PDN, 0);
 			if (ret < 0)
 				return ret;
 		}
@@ -378,7 +380,7 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream,
 
 	val |= cs4271_clk_tab[i].ratio_mask;
 
-	ret = snd_soc_update_bits(codec, CS4271_MODE1,
+	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE1,
 		CS4271_MODE1_MODE_MASK | CS4271_MODE1_DIV_MASK, val);
 	if (ret < 0)
 		return ret;
@@ -386,22 +388,29 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream,
 	return cs4271_set_deemph(codec);
 }
 
-static int cs4271_digital_mute(struct snd_soc_dai *dai, int mute)
+static int cs4271_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
 {
 	struct snd_soc_codec *codec = dai->codec;
+	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
 	int ret;
 	int val_a = 0;
 	int val_b = 0;
 
+	if (stream != SNDRV_PCM_STREAM_PLAYBACK)
+		return 0;
+
 	if (mute) {
 		val_a = CS4271_VOLA_MUTE;
 		val_b = CS4271_VOLB_MUTE;
 	}
 
-	ret = snd_soc_update_bits(codec, CS4271_VOLA, CS4271_VOLA_MUTE, val_a);
+	ret = regmap_update_bits(cs4271->regmap, CS4271_VOLA,
+				 CS4271_VOLA_MUTE, val_a);
 	if (ret < 0)
 		return ret;
-	ret = snd_soc_update_bits(codec, CS4271_VOLB, CS4271_VOLB_MUTE, val_b);
+
+	ret = regmap_update_bits(cs4271->regmap, CS4271_VOLB,
+				 CS4271_VOLB_MUTE, val_b);
 	if (ret < 0)
 		return ret;
 
@@ -436,7 +445,7 @@ static const struct snd_soc_dai_ops cs4271_dai_ops = {
 	.hw_params	= cs4271_hw_params,
 	.set_sysclk	= cs4271_set_dai_sysclk,
 	.set_fmt	= cs4271_set_dai_fmt,
-	.digital_mute	= cs4271_digital_mute,
+	.mute_stream	= cs4271_mute_stream,
 };
 
 static struct snd_soc_dai_driver cs4271_dai = {
@@ -463,25 +472,33 @@ static struct snd_soc_dai_driver cs4271_dai = {
 static int cs4271_soc_suspend(struct snd_soc_codec *codec)
 {
 	int ret;
+	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+
 	/* Set power-down bit */
-	ret = snd_soc_update_bits(codec, CS4271_MODE2, CS4271_MODE2_PDN,
-				  CS4271_MODE2_PDN);
+	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
+				 CS4271_MODE2_PDN, CS4271_MODE2_PDN);
 	if (ret < 0)
 		return ret;
+
 	return 0;
 }
 
 static int cs4271_soc_resume(struct snd_soc_codec *codec)
 {
 	int ret;
+	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+
 	/* Restore codec state */
-	ret = snd_soc_cache_sync(codec);
+	ret = regcache_sync(cs4271->regmap);
 	if (ret < 0)
 		return ret;
+
 	/* then disable the power-down bit */
-	ret = snd_soc_update_bits(codec, CS4271_MODE2, CS4271_MODE2_PDN, 0);
+	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
+				 CS4271_MODE2_PDN, 0);
 	if (ret < 0)
 		return ret;
+
 	return 0;
 }
 #else
@@ -542,40 +559,22 @@ static int cs4271_probe(struct snd_soc_codec *codec)
 
 	cs4271->gpio_nreset = gpio_nreset;
 
-	/*
-	 * In case of I2C, chip address specified in board data.
-	 * So cache IO operations use 8 bit codec register address.
-	 * In case of SPI, chip address and register address
-	 * passed together as 16 bit value.
-	 * Anyway, register address is masked with 0xFF inside
-	 * soc-cache code.
-	 */
-	if (cs4271->bus_type == SND_SOC_SPI)
-		ret = snd_soc_codec_set_cache_io(codec, 16, 8,
-			cs4271->bus_type);
-	else
-		ret = snd_soc_codec_set_cache_io(codec, 8, 8,
-			cs4271->bus_type);
-	if (ret) {
-		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-		return ret;
-	}
-
-	ret = snd_soc_update_bits(codec, CS4271_MODE2,
-				  CS4271_MODE2_PDN | CS4271_MODE2_CPEN,
-				  CS4271_MODE2_PDN | CS4271_MODE2_CPEN);
+	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
+				 CS4271_MODE2_PDN | CS4271_MODE2_CPEN,
+				 CS4271_MODE2_PDN | CS4271_MODE2_CPEN);
 	if (ret < 0)
 		return ret;
-	ret = snd_soc_update_bits(codec, CS4271_MODE2, CS4271_MODE2_PDN, 0);
+	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
+				 CS4271_MODE2_PDN, 0);
 	if (ret < 0)
 		return ret;
 	/* Power-up sequence requires 85 uS */
 	udelay(85);
 
 	if (amutec_eq_bmutec)
-		snd_soc_update_bits(codec, CS4271_MODE2,
-				    CS4271_MODE2_MUTECAEQUB,
-				    CS4271_MODE2_MUTECAEQUB);
+		regmap_update_bits(cs4271->regmap, CS4271_MODE2,
+				   CS4271_MODE2_MUTECAEQUB,
+				   CS4271_MODE2_MUTECAEQUB);
 
 	return snd_soc_add_codec_controls(codec, cs4271_snd_controls,
 		ARRAY_SIZE(cs4271_snd_controls));
@@ -597,13 +596,24 @@ static struct snd_soc_codec_driver soc_codec_dev_cs4271 = {
 	.remove			= cs4271_remove,
 	.suspend		= cs4271_soc_suspend,
 	.resume			= cs4271_soc_resume,
-	.reg_cache_default	= cs4271_dflt_reg,
-	.reg_cache_size		= ARRAY_SIZE(cs4271_dflt_reg),
-	.reg_word_size		= sizeof(cs4271_dflt_reg[0]),
-	.compress_type		= SND_SOC_FLAT_COMPRESSION,
 };
 
 #if defined(CONFIG_SPI_MASTER)
+
+static const struct regmap_config cs4271_spi_regmap = {
+	.reg_bits = 16,
+	.val_bits = 8,
+	.max_register = CS4271_LASTREG,
+	.read_flag_mask = 0x21,
+	.write_flag_mask = 0x20,
+
+	.reg_defaults = cs4271_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = cs4271_volatile_reg,
+};
+
 static int cs4271_spi_probe(struct spi_device *spi)
 {
 	struct cs4271_private *cs4271;
@@ -613,7 +623,9 @@ static int cs4271_spi_probe(struct spi_device *spi)
 		return -ENOMEM;
 
 	spi_set_drvdata(spi, cs4271);
-	cs4271->bus_type = SND_SOC_SPI;
+	cs4271->regmap = devm_regmap_init_spi(spi, &cs4271_spi_regmap);
+	if (IS_ERR(cs4271->regmap))
+		return PTR_ERR(cs4271->regmap);
 
 	return snd_soc_register_codec(&spi->dev, &soc_codec_dev_cs4271,
 		&cs4271_dai, 1);
@@ -643,6 +655,18 @@ static const struct i2c_device_id cs4271_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id);
 
+static const struct regmap_config cs4271_i2c_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = CS4271_LASTREG,
+
+	.reg_defaults = cs4271_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = cs4271_volatile_reg,
+};
+
 static int cs4271_i2c_probe(struct i2c_client *client,
 			    const struct i2c_device_id *id)
 {
@@ -653,7 +677,9 @@ static int cs4271_i2c_probe(struct i2c_client *client,
 		return -ENOMEM;
 
 	i2c_set_clientdata(client, cs4271);
-	cs4271->bus_type = SND_SOC_I2C;
+	cs4271->regmap = devm_regmap_init_i2c(client, &cs4271_i2c_regmap);
+	if (IS_ERR(cs4271->regmap))
+		return PTR_ERR(cs4271->regmap);
 
 	return snd_soc_register_codec(&client->dev, &soc_codec_dev_cs4271,
 		&cs4271_dai, 1);
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index 6361dab48bd1..3b20c86cdb01 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -1180,7 +1180,11 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream,
 		priv->config[id].mmcc &= 0xC0;
 		priv->config[id].mmcc |= cs42l73_mclk_coeffs[mclk_coeff].mmcc;
 		priv->config[id].spc &= 0xFC;
-		priv->config[id].spc |= MCK_SCLK_MCLK;
+		/* Use SCLK=64*Fs if internal MCLK >= 6.4MHz */
+		if (priv->mclk >= 6400000)
+			priv->config[id].spc |= MCK_SCLK_64FS;
+		else
+			priv->config[id].spc |= MCK_SCLK_MCLK;
 	} else {
 		/* CS42L73 Slave */
 		priv->config[id].spc &= 0xFC;
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index a4c16fd70f77..3eeada57e87d 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -739,14 +739,32 @@ static const unsigned int max98088_micboost_tlv[] = {
        2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
 };
 
+static const unsigned int max98088_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 max98088_spk_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 struct snd_kcontrol_new max98088_snd_controls[] = {
 
-       SOC_DOUBLE_R("Headphone Volume", M98088_REG_39_LVL_HP_L,
-               M98088_REG_3A_LVL_HP_R, 0, 31, 0),
-       SOC_DOUBLE_R("Speaker Volume", M98088_REG_3D_LVL_SPK_L,
-               M98088_REG_3E_LVL_SPK_R, 0, 31, 0),
-       SOC_DOUBLE_R("Receiver Volume", M98088_REG_3B_LVL_REC_L,
-               M98088_REG_3C_LVL_REC_R, 0, 31, 0),
+	SOC_DOUBLE_R_TLV("Headphone Volume", M98088_REG_39_LVL_HP_L,
+			 M98088_REG_3A_LVL_HP_R, 0, 31, 0, max98088_hp_tlv),
+	SOC_DOUBLE_R_TLV("Speaker Volume", M98088_REG_3D_LVL_SPK_L,
+			 M98088_REG_3E_LVL_SPK_R, 0, 31, 0, max98088_spk_tlv),
+	SOC_DOUBLE_R_TLV("Receiver Volume", M98088_REG_3B_LVL_REC_L,
+			 M98088_REG_3C_LVL_REC_R, 0, 31, 0, max98088_spk_tlv),
 
        SOC_DOUBLE_R("Headphone Switch", M98088_REG_39_LVL_HP_L,
                M98088_REG_3A_LVL_HP_R, 7, 1, 1),
@@ -2006,7 +2024,7 @@ static int max98088_probe(struct snd_soc_codec *codec)
                        ret);
                goto err_access;
        }
-       dev_info(codec->dev, "revision %c\n", ret + 'A');
+       dev_info(codec->dev, "revision %c\n", ret - 0x40 + 'A');
 
        snd_soc_write(codec, M98088_REG_51_PWR_SYS, M98088_PWRSV);
 
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index fc176044994d..ce0d36412c97 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -23,8 +23,6 @@
 #include <sound/max98090.h>
 #include "max98090.h"
 
-#include <linux/version.h>
-
 #define DEBUG
 #define EXTMIC_METHOD
 #define EXTMIC_METHOD_TEST
@@ -509,16 +507,16 @@ static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
-static const char * max98090_perf_pwr_text[] =
+static const char *max98090_perf_pwr_text[] =
 	{ "High Performance", "Low Power" };
-static const char * max98090_pwr_perf_text[] =
+static const char *max98090_pwr_perf_text[] =
 	{ "Low Power", "High Performance" };
 
 static const struct soc_enum max98090_vcmbandgap_enum =
 	SOC_ENUM_SINGLE(M98090_REG_BIAS_CONTROL, M98090_VCM_MODE_SHIFT,
 		ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text);
 
-static const char * max98090_osr128_text[] = { "64*fs", "128*fs" };
+static const char *max98090_osr128_text[] = { "64*fs", "128*fs" };
 
 static const struct soc_enum max98090_osr128_enum =
 	SOC_ENUM_SINGLE(M98090_REG_ADC_CONTROL, M98090_OSR128_SHIFT,
@@ -535,28 +533,28 @@ static const struct soc_enum max98090_filter_dmic34mode_enum =
 		M98090_FLT_DMIC34MODE_SHIFT,
 		ARRAY_SIZE(max98090_mode_text), max98090_mode_text);
 
-static const char * max98090_drcatk_text[] =
+static const char *max98090_drcatk_text[] =
 	{ "0.5ms", "1ms", "5ms", "10ms", "25ms", "50ms", "100ms", "200ms" };
 
 static const struct soc_enum max98090_drcatk_enum =
 	SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCATK_SHIFT,
 		ARRAY_SIZE(max98090_drcatk_text), max98090_drcatk_text);
 
-static const char * max98090_drcrls_text[] =
+static const char *max98090_drcrls_text[] =
 	{ "8s", "4s", "2s", "1s", "0.5s", "0.25s", "0.125s", "0.0625s" };
 
 static const struct soc_enum max98090_drcrls_enum =
 	SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCRLS_SHIFT,
 		ARRAY_SIZE(max98090_drcrls_text), max98090_drcrls_text);
 
-static const char * max98090_alccmp_text[] =
+static const char *max98090_alccmp_text[] =
 	{ "1:1", "1:1.5", "1:2", "1:4", "1:INF" };
 
 static const struct soc_enum max98090_alccmp_enum =
 	SOC_ENUM_SINGLE(M98090_REG_DRC_COMPRESSOR, M98090_DRCCMP_SHIFT,
 		ARRAY_SIZE(max98090_alccmp_text), max98090_alccmp_text);
 
-static const char * max98090_drcexp_text[] = { "1:1", "2:1", "3:1" };
+static const char *max98090_drcexp_text[] = { "1:1", "2:1", "3:1" };
 
 static const struct soc_enum max98090_drcexp_enum =
 	SOC_ENUM_SINGLE(M98090_REG_DRC_EXPANDER, M98090_DRCEXP_SHIFT,
@@ -859,7 +857,7 @@ static const struct soc_enum mic2_mux_enum =
 static const struct snd_kcontrol_new max98090_mic2_mux =
 	SOC_DAPM_ENUM("MIC2 Mux", mic2_mux_enum);
 
-static const char * max98090_micpre_text[] = { "Off", "On" };
+static const char *max98090_micpre_text[] = { "Off", "On" };
 
 static const struct soc_enum max98090_pa1en_enum =
 	SOC_ENUM_SINGLE(M98090_REG_MIC1_INPUT_LEVEL, M98090_MIC_PA1EN_SHIFT,
@@ -1703,9 +1701,8 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
 		 * seen for the case of TDM mode. The remaining cases have
 		 * normal logic.
 		 */
-		if (max98090->tdm_slots > 1) {
+		if (max98090->tdm_slots > 1)
 			regval ^= M98090_BCI_MASK;
-		}
 
 		snd_soc_write(codec,
 			M98090_REG_INTERFACE_FORMAT, regval);
@@ -2059,17 +2056,14 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
 	if (!active)
 		return IRQ_NONE;
 
-	if (active & M98090_CLD_MASK) {
+	if (active & M98090_CLD_MASK)
 		dev_err(codec->dev, "M98090_CLD_MASK\n");
-	}
 
-	if (active & M98090_SLD_MASK) {
+	if (active & M98090_SLD_MASK)
 		dev_dbg(codec->dev, "M98090_SLD_MASK\n");
-	}
 
-	if (active & M98090_ULK_MASK) {
+	if (active & M98090_ULK_MASK)
 		dev_err(codec->dev, "M98090_ULK_MASK\n");
-	}
 
 	if (active & M98090_JDET_MASK) {
 		dev_dbg(codec->dev, "M98090_JDET_MASK\n");
@@ -2080,13 +2074,11 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
 			msecs_to_jiffies(100));
 	}
 
-	if (active & M98090_DRCACT_MASK) {
+	if (active & M98090_DRCACT_MASK)
 		dev_dbg(codec->dev, "M98090_DRCACT_MASK\n");
-	}
 
-	if (active & M98090_DRCCLP_MASK) {
+	if (active & M98090_DRCCLP_MASK)
 		dev_err(codec->dev, "M98090_DRCCLP_MASK\n");
-	}
 
 	return IRQ_HANDLED;
 }
@@ -2324,7 +2316,7 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
 	max98090->pdata = i2c->dev.platform_data;
 	max98090->irq = i2c->irq;
 
-	max98090->regmap = regmap_init_i2c(i2c, &max98090_regmap);
+	max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap);
 	if (IS_ERR(max98090->regmap)) {
 		ret = PTR_ERR(max98090->regmap);
 		dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
@@ -2334,18 +2326,13 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
 	ret = snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_max98090, max98090_dai,
 			ARRAY_SIZE(max98090_dai));
-	if (ret < 0)
-		regmap_exit(max98090->regmap);
-
 err_enable:
 	return ret;
 }
 
 static int max98090_i2c_remove(struct i2c_client *client)
 {
-	struct max98090_priv *max98090 = dev_get_drvdata(&client->dev);
 	snd_soc_unregister_codec(&client->dev);
-	regmap_exit(max98090->regmap);
 	return 0;
 }
 
@@ -2369,7 +2356,7 @@ static int max98090_runtime_suspend(struct device *dev)
 	return 0;
 }
 
-static struct dev_pm_ops max98090_pm = {
+static const struct dev_pm_ops max98090_pm = {
 	SET_RUNTIME_PM_OPS(max98090_runtime_suspend,
 		max98090_runtime_resume, NULL)
 };
diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c
index 566ea3256e2d..721587c9cd84 100644
--- a/sound/soc/codecs/si476x.c
+++ b/sound/soc/codecs/si476x.c
@@ -1,3 +1,22 @@
+/*
+ * sound/soc/codecs/si476x.c -- Codec driver for SI476X chips
+ *
+ * Copyright (C) 2012 Innovative Converged Devices(ICD)
+ * Copyright (C) 2013 Andrey Smirnov
+ *
+ * Author: Andrey Smirnov <andrew.smirnov@gmail.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; version 2 of the License.
+ *
+ * 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.
+ *
+ */
+
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <sound/pcm.h>
@@ -45,13 +64,23 @@ static unsigned int si476x_codec_read(struct snd_soc_codec *codec,
 				      unsigned int reg)
 {
 	int err;
+	unsigned int val;
 	struct si476x_core *core = codec->control_data;
 
 	si476x_core_lock(core);
-	err = si476x_core_cmd_get_property(core, reg);
+	if (!si476x_core_is_powered_up(core))
+		regcache_cache_only(core->regmap, true);
+
+	err = regmap_read(core->regmap, reg, &val);
+
+	if (!si476x_core_is_powered_up(core))
+		regcache_cache_only(core->regmap, false);
 	si476x_core_unlock(core);
 
-	return err;
+	if (err < 0)
+		return err;
+
+	return val;
 }
 
 static int si476x_codec_write(struct snd_soc_codec *codec,
@@ -61,7 +90,13 @@ static int si476x_codec_write(struct snd_soc_codec *codec,
 	struct si476x_core *core = codec->control_data;
 
 	si476x_core_lock(core);
-	err = si476x_core_cmd_set_property(core, reg, val);
+	if (!si476x_core_is_powered_up(core))
+		regcache_cache_only(core->regmap, true);
+
+	err = regmap_write(core->regmap, reg, val);
+
+	if (!si476x_core_is_powered_up(core))
+		regcache_cache_only(core->regmap, false);
 	si476x_core_unlock(core);
 
 	return err;
@@ -140,7 +175,7 @@ static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		dev_err(codec_dai->codec->dev, "Failed to set output format\n");
 		return err;
 	}
-	
+
 	return 0;
 }
 
@@ -182,7 +217,7 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream,
 
 	err = snd_soc_update_bits(dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT,
 				  SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK,
-				  (width << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) | 
+				  (width << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) |
 				  (width << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT));
 	if (err < 0) {
 		dev_err(dai->codec->dev, "Failed to set output width\n");
@@ -251,6 +286,6 @@ static struct platform_driver si476x_platform_driver = {
 };
 module_platform_driver(si476x_platform_driver);
 
-MODULE_AUTHOR("Andrey Smirnov <andrey.smirnov@convergeddevices.net>");
+MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
 MODULE_DESCRIPTION("ASoC Si4761/64 codec driver");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c
new file mode 100644
index 000000000000..d447c4aa1d5e
--- /dev/null
+++ b/sound/soc/codecs/tas5086.c
@@ -0,0 +1,591 @@
+/*
+ * TAS5086 ASoC codec driver
+ *
+ * Copyright (c) 2013 Daniel Mack <zonque@gmail.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.
+ *
+ * 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.
+ *
+ * TODO:
+ *  - implement DAPM and input muxing
+ *  - implement modulation limit
+ *  - implement non-default PWM start
+ *
+ * Note that this chip has a very unusual register layout, specifically
+ * because the registers are of unequal size, and multi-byte registers
+ * require bulk writes to take effect. Regmap does not support that kind
+ * of devices.
+ *
+ * Currently, the driver does not touch any of the registers >= 0x20, so
+ * it doesn't matter because the entire map can be accessed as 8-bit
+ * array. In case more features will be added in the future
+ * that require access to higher registers, the entire regmap H/W I/O
+ * routines have to be open-coded.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/tas5086.h>
+
+#define TAS5086_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE  |		\
+			     SNDRV_PCM_FMTBIT_S20_3LE |		\
+			     SNDRV_PCM_FMTBIT_S24_3LE)
+
+#define TAS5086_PCM_RATES   (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100  | \
+			     SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200  | \
+			     SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
+			     SNDRV_PCM_RATE_192000)
+
+/*
+ * TAS5086 registers
+ */
+#define TAS5086_CLOCK_CONTROL		0x00	/* Clock control register  */
+#define TAS5086_CLOCK_RATE(val)		(val << 5)
+#define TAS5086_CLOCK_RATE_MASK		(0x7 << 5)
+#define TAS5086_CLOCK_RATIO(val)	(val << 2)
+#define TAS5086_CLOCK_RATIO_MASK	(0x7 << 2)
+#define TAS5086_CLOCK_SCLK_RATIO_48	(1 << 1)
+#define TAS5086_CLOCK_VALID		(1 << 0)
+
+#define TAS5086_DEEMPH_MASK		0x03
+#define TAS5086_SOFT_MUTE_ALL		0x3f
+
+#define TAS5086_DEV_ID			0x01	/* Device ID register */
+#define TAS5086_ERROR_STATUS		0x02	/* Error status register */
+#define TAS5086_SYS_CONTROL_1		0x03	/* System control register 1 */
+#define TAS5086_SERIAL_DATA_IF		0x04	/* Serial data interface register  */
+#define TAS5086_SYS_CONTROL_2		0x05	/* System control register 2 */
+#define TAS5086_SOFT_MUTE		0x06	/* Soft mute register */
+#define TAS5086_MASTER_VOL		0x07	/* Master volume  */
+#define TAS5086_CHANNEL_VOL(X)		(0x08 + (X))	/* Channel 1-6 volume */
+#define TAS5086_VOLUME_CONTROL		0x09	/* Volume control register */
+#define TAS5086_MOD_LIMIT		0x10	/* Modulation limit register */
+#define TAS5086_PWM_START		0x18	/* PWM start register */
+#define TAS5086_SURROUND		0x19	/* Surround register */
+#define TAS5086_SPLIT_CAP_CHARGE	0x1a	/* Split cap charge period register */
+#define TAS5086_OSC_TRIM		0x1b	/* Oscillator trim register */
+#define TAS5086_BKNDERR 		0x1c
+
+/*
+ * Default TAS5086 power-up configuration
+ */
+static const struct reg_default tas5086_reg_defaults[] = {
+	{ 0x00,	0x6c },
+	{ 0x01,	0x03 },
+	{ 0x02,	0x00 },
+	{ 0x03,	0xa0 },
+	{ 0x04,	0x05 },
+	{ 0x05,	0x60 },
+	{ 0x06,	0x00 },
+	{ 0x07,	0xff },
+	{ 0x08,	0x30 },
+	{ 0x09,	0x30 },
+	{ 0x0a,	0x30 },
+	{ 0x0b,	0x30 },
+	{ 0x0c,	0x30 },
+	{ 0x0d,	0x30 },
+	{ 0x0e,	0xb1 },
+	{ 0x0f,	0x00 },
+	{ 0x10,	0x02 },
+	{ 0x11,	0x00 },
+	{ 0x12,	0x00 },
+	{ 0x13,	0x00 },
+	{ 0x14,	0x00 },
+	{ 0x15,	0x00 },
+	{ 0x16,	0x00 },
+	{ 0x17,	0x00 },
+	{ 0x18,	0x3f },
+	{ 0x19,	0x00 },
+	{ 0x1a,	0x18 },
+	{ 0x1b,	0x82 },
+	{ 0x1c,	0x05 },
+};
+
+static bool tas5086_accessible_reg(struct device *dev, unsigned int reg)
+{
+	return !((reg == 0x0f) || (reg >= 0x11 && reg <= 0x17));
+}
+
+static bool tas5086_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS5086_DEV_ID:
+	case TAS5086_ERROR_STATUS:
+		return true;
+	}
+
+	return false;
+}
+
+static bool tas5086_writeable_reg(struct device *dev, unsigned int reg)
+{
+	return tas5086_accessible_reg(dev, reg) && (reg != TAS5086_DEV_ID);
+}
+
+struct tas5086_private {
+	struct regmap	*regmap;
+	unsigned int	mclk, sclk;
+	unsigned int	format;
+	bool		deemph;
+	/* Current sample rate for de-emphasis control */
+	int		rate;
+	/* GPIO driving Reset pin, if any */
+	int		gpio_nreset;
+};
+
+static int tas5086_deemph[] = { 0, 32000, 44100, 48000 };
+
+static int tas5086_set_deemph(struct snd_soc_codec *codec)
+{
+	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+	int i, val = 0;
+
+	if (priv->deemph)
+		for (i = 0; i < ARRAY_SIZE(tas5086_deemph); i++)
+			if (tas5086_deemph[i] == priv->rate)
+				val = i;
+
+	return regmap_update_bits(priv->regmap, TAS5086_SYS_CONTROL_1,
+				  TAS5086_DEEMPH_MASK, val);
+}
+
+static int tas5086_get_deemph(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.enumerated.item[0] = priv->deemph;
+
+	return 0;
+}
+
+static int tas5086_put_deemph(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+
+	priv->deemph = ucontrol->value.enumerated.item[0];
+
+	return tas5086_set_deemph(codec);
+}
+
+
+static int tas5086_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 tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+
+	switch (clk_id) {
+	case TAS5086_CLK_IDX_MCLK:
+		priv->mclk = freq;
+		break;
+	case TAS5086_CLK_IDX_SCLK:
+		priv->sclk = freq;
+		break;
+	}
+
+	return 0;
+}
+
+static int tas5086_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			       unsigned int format)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+
+	/* The TAS5086 can only be slave to all clocks */
+	if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
+		dev_err(codec->dev, "Invalid clocking mode\n");
+		return -EINVAL;
+	}
+
+	/* we need to refer to the data format from hw_params() */
+	priv->format = format;
+
+	return 0;
+}
+
+static const int tas5086_sample_rates[] = {
+	32000, 38000, 44100, 48000, 88200, 96000, 176400, 192000
+};
+
+static const int tas5086_ratios[] = {
+	64, 128, 192, 256, 384, 512
+};
+
+static int index_in_array(const int *array, int len, int needle)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		if (array[i] == needle)
+			return i;
+
+	return -ENOENT;
+}
+
+static int tas5086_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 tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+	int val;
+	int ret;
+
+	priv->rate = params_rate(params);
+
+	/* Look up the sample rate and refer to the offset in the list */
+	val = index_in_array(tas5086_sample_rates,
+			     ARRAY_SIZE(tas5086_sample_rates), priv->rate);
+
+	if (val < 0) {
+		dev_err(codec->dev, "Invalid sample rate\n");
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL,
+				 TAS5086_CLOCK_RATE_MASK,
+				 TAS5086_CLOCK_RATE(val));
+	if (ret < 0)
+		return ret;
+
+	/* MCLK / Fs ratio */
+	val = index_in_array(tas5086_ratios, ARRAY_SIZE(tas5086_ratios),
+			     priv->mclk / priv->rate);
+	if (val < 0) {
+		dev_err(codec->dev, "Inavlid MCLK / Fs ratio\n");
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL,
+				 TAS5086_CLOCK_RATIO_MASK,
+				 TAS5086_CLOCK_RATIO(val));
+	if (ret < 0)
+		return ret;
+
+
+	ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL,
+				 TAS5086_CLOCK_SCLK_RATIO_48,
+				 (priv->sclk == 48 * priv->rate) ? 
+					TAS5086_CLOCK_SCLK_RATIO_48 : 0);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * The chip has a very unituitive register mapping and muxes information
+	 * about data format and sample depth into the same register, but not on
+	 * a logical bit-boundary. Hence, we have to refer to the format passed
+	 * in the set_dai_fmt() callback and set up everything from here.
+	 *
+	 * First, determine the 'base' value, using the format ...
+	 */
+	switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_RIGHT_J:
+		val = 0x00;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		val = 0x03;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		val = 0x06;
+		break;
+	default:
+		dev_err(codec->dev, "Invalid DAI format\n");
+		return -EINVAL;
+	}
+
+	/* ... then add the offset for the sample bit depth. */
+	switch (params_format(params)) {
+        case SNDRV_PCM_FORMAT_S16_LE:
+		val += 0;
+                break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		val += 1;
+		break;
+	case SNDRV_PCM_FORMAT_S24_3LE:
+		val += 2;
+		break;
+	default:
+		dev_err(codec->dev, "Invalid bit width\n");
+		return -EINVAL;
+	};
+
+	ret = regmap_write(priv->regmap, TAS5086_SERIAL_DATA_IF, val);
+	if (ret < 0)
+		return ret;
+
+	/* clock is considered valid now */
+	ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL,
+				 TAS5086_CLOCK_VALID, TAS5086_CLOCK_VALID);
+	if (ret < 0)
+		return ret;
+
+	return tas5086_set_deemph(codec);
+}
+
+static int tas5086_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+	unsigned int val = 0;
+
+	if (mute)
+		val = TAS5086_SOFT_MUTE_ALL;
+
+	return regmap_write(priv->regmap, TAS5086_SOFT_MUTE, val);
+}
+
+/* TAS5086 controls */
+static const DECLARE_TLV_DB_SCALE(tas5086_dac_tlv, -10350, 50, 1);
+
+static const struct snd_kcontrol_new tas5086_controls[] = {
+	SOC_SINGLE_TLV("Master Playback Volume", TAS5086_MASTER_VOL,
+		       0, 0xff, 1, tas5086_dac_tlv),
+	SOC_DOUBLE_R_TLV("Channel 1/2 Playback Volume",
+			 TAS5086_CHANNEL_VOL(0), TAS5086_CHANNEL_VOL(1),
+			 0, 0xff, 1, tas5086_dac_tlv),
+	SOC_DOUBLE_R_TLV("Channel 3/4 Playback Volume",
+			 TAS5086_CHANNEL_VOL(2), TAS5086_CHANNEL_VOL(3),
+			 0, 0xff, 1, tas5086_dac_tlv),
+	SOC_DOUBLE_R_TLV("Channel 5/6 Playback Volume",
+			 TAS5086_CHANNEL_VOL(4), TAS5086_CHANNEL_VOL(5),
+			 0, 0xff, 1, tas5086_dac_tlv),
+	SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0,
+			    tas5086_get_deemph, tas5086_put_deemph),
+};
+
+static const struct snd_soc_dai_ops tas5086_dai_ops = {
+	.hw_params	= tas5086_hw_params,
+	.set_sysclk	= tas5086_set_dai_sysclk,
+	.set_fmt	= tas5086_set_dai_fmt,
+	.mute_stream	= tas5086_mute_stream,
+};
+
+static struct snd_soc_dai_driver tas5086_dai = {
+	.name = "tas5086-hifi",
+	.playback = {
+		.stream_name	= "Playback",
+		.channels_min	= 2,
+		.channels_max	= 6,
+		.rates		= TAS5086_PCM_RATES,
+		.formats	= TAS5086_PCM_FORMATS,
+	},
+	.ops = &tas5086_dai_ops,
+};
+
+#ifdef CONFIG_PM
+static int tas5086_soc_resume(struct snd_soc_codec *codec)
+{
+	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+
+	/* Restore codec state */
+	return regcache_sync(priv->regmap);
+}
+#else
+#define tas5086_soc_resume	NULL
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_OF
+static const struct of_device_id tas5086_dt_ids[] = {
+	{ .compatible = "ti,tas5086", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, tas5086_dt_ids);
+#endif
+
+/* charge period values in microseconds */
+static const int tas5086_charge_period[] = {
+	  13000,  16900,   23400,   31200,   41600,   54600,   72800,   96200,
+	 130000, 156000,  234000,  312000,  416000,  546000,  728000,  962000,
+	1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000,
+};
+
+static int tas5086_probe(struct snd_soc_codec *codec)
+{
+	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+	int charge_period = 1300000; /* hardware default is 1300 ms */
+	int i, ret;
+
+	if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) {
+		struct device_node *of_node = codec->dev->of_node;
+		of_property_read_u32(of_node, "ti,charge-period", &charge_period);
+	}
+
+	/* lookup and set split-capacitor charge period */
+	if (charge_period == 0) {
+		regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0);
+	} else {
+		i = index_in_array(tas5086_charge_period,
+				   ARRAY_SIZE(tas5086_charge_period),
+				   charge_period);
+		if (i >= 0)
+			regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE,
+				     i + 0x08);
+		else
+			dev_warn(codec->dev,
+				 "Invalid split-cap charge period of %d ns.\n",
+				 charge_period);
+	}
+
+	/* enable factory trim */
+	ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00);
+	if (ret < 0)
+		return ret;
+
+	/* start all channels */
+	ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20);
+	if (ret < 0)
+		return ret;
+
+	/* set master volume to 0 dB */
+	ret = regmap_write(priv->regmap, TAS5086_MASTER_VOL, 0x30);
+	if (ret < 0)
+		return ret;
+
+	/* mute all channels for now */
+	ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE,
+			   TAS5086_SOFT_MUTE_ALL);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int tas5086_remove(struct snd_soc_codec *codec)
+{
+	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+
+	if (gpio_is_valid(priv->gpio_nreset))
+		/* Set codec to the reset state */
+		gpio_set_value(priv->gpio_nreset, 0);
+
+	return 0;
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_tas5086 = {
+	.probe			= tas5086_probe,
+	.remove			= tas5086_remove,
+	.resume			= tas5086_soc_resume,
+	.controls		= tas5086_controls,
+	.num_controls		= ARRAY_SIZE(tas5086_controls),
+};
+
+static const struct i2c_device_id tas5086_i2c_id[] = {
+	{ "tas5086", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tas5086_i2c_id);
+
+static const struct regmap_config tas5086_regmap = {
+	.reg_bits		= 8,
+	.val_bits		= 8,
+	.max_register		= ARRAY_SIZE(tas5086_reg_defaults),
+	.reg_defaults		= tas5086_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(tas5086_reg_defaults),
+	.cache_type		= REGCACHE_RBTREE,
+	.volatile_reg		= tas5086_volatile_reg,
+	.writeable_reg		= tas5086_writeable_reg,
+	.readable_reg		= tas5086_accessible_reg,
+};
+
+static int tas5086_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	struct tas5086_private *priv;
+	struct device *dev = &i2c->dev;
+	int gpio_nreset = -EINVAL;
+	int i, ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->regmap = devm_regmap_init_i2c(i2c, &tas5086_regmap);
+	if (IS_ERR(priv->regmap)) {
+		ret = PTR_ERR(priv->regmap);
+		dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret);
+		return ret;
+	}
+
+	i2c_set_clientdata(i2c, priv);
+
+	if (of_match_device(of_match_ptr(tas5086_dt_ids), dev)) {
+		struct device_node *of_node = dev->of_node;
+		gpio_nreset = of_get_named_gpio(of_node, "reset-gpio", 0);
+	}
+
+	if (gpio_is_valid(gpio_nreset))
+		if (devm_gpio_request(dev, gpio_nreset, "TAS5086 Reset"))
+			gpio_nreset = -EINVAL;
+
+	if (gpio_is_valid(gpio_nreset)) {
+		/* Reset codec - minimum assertion time is 400ns */
+		gpio_direction_output(gpio_nreset, 0);
+		udelay(1);
+		gpio_set_value(gpio_nreset, 1);
+
+		/* Codec needs ~15ms to wake up */
+		msleep(15);
+	}
+
+	priv->gpio_nreset = gpio_nreset;
+
+	/* The TAS5086 always returns 0x03 in its TAS5086_DEV_ID register */
+	ret = regmap_read(priv->regmap, TAS5086_DEV_ID, &i);
+	if (ret < 0)
+		return ret;
+
+	if (i != 0x3) {
+		dev_err(dev,
+			"Failed to identify TAS5086 codec (got %02x)\n", i);
+		return -ENODEV;
+	}
+
+	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_tas5086,
+		&tas5086_dai, 1);
+}
+
+static int tas5086_i2c_remove(struct i2c_client *i2c)
+{
+	snd_soc_unregister_codec(&i2c->dev);
+	return 0;
+}
+
+static struct i2c_driver tas5086_i2c_driver = {
+	.driver = {
+		.name	= "tas5086",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(tas5086_dt_ids),
+	},
+	.id_table	= tas5086_i2c_id,
+	.probe		= tas5086_i2c_probe,
+	.remove		= tas5086_i2c_remove,
+};
+
+module_i2c_driver(tas5086_i2c_driver);
+
+MODULE_AUTHOR("Daniel Mack <zonque@gmail.com>");
+MODULE_DESCRIPTION("Texas Instruments TAS5086 ALSA SoC Codec Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c
index ad2fee4bb4cd..8df2b6e1a1a6 100644
--- a/sound/soc/codecs/wm0010.c
+++ b/sound/soc/codecs/wm0010.c
@@ -342,7 +342,7 @@ static void byte_swap_64(u64 *data_in, u64 *data_out, u32 len)
 		data_out[i] = cpu_to_be64(le64_to_cpu(data_in[i]));
 }
 
-static int wm0010_firmware_load(char *name, struct snd_soc_codec *codec)
+static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec)
 {
 	struct spi_device *spi = to_spi_device(codec->dev);
 	struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
@@ -361,8 +361,8 @@ static int wm0010_firmware_load(char *name, struct snd_soc_codec *codec)
 
 	ret = request_firmware(&fw, name, codec->dev);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to request application: %d\n",
-			ret);
+		dev_err(codec->dev, "Failed to request application(%s): %d\n",
+			name, ret);
 		return ret;
 	}
 
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c
index f2ac38b61a1b..7fefd766b582 100644
--- a/sound/soc/codecs/wm2000.c
+++ b/sound/soc/codecs/wm2000.c
@@ -761,6 +761,8 @@ static bool wm2000_readable_reg(struct device *dev, unsigned int reg)
 	case WM2000_REG_SYS_CTL2:
 	case WM2000_REG_ANC_STAT:
 	case WM2000_REG_IF_CTL:
+	case WM2000_REG_ANA_MIC_CTL:
+	case WM2000_REG_SPK_CTL:
 		return true;
 	default:
 		return false;
@@ -771,7 +773,7 @@ static const struct regmap_config wm2000_regmap = {
 	.reg_bits = 16,
 	.val_bits = 8,
 
-	.max_register = WM2000_REG_IF_CTL,
+	.max_register = WM2000_REG_SPK_CTL,
 	.readable_reg = wm2000_readable_reg,
 };
 
diff --git a/sound/soc/codecs/wm2000.h b/sound/soc/codecs/wm2000.h
index fb812cd9e77d..3870c0e1d246 100644
--- a/sound/soc/codecs/wm2000.h
+++ b/sound/soc/codecs/wm2000.h
@@ -30,6 +30,8 @@
 #define WM2000_REG_SYS_CTL2         0xf004
 #define WM2000_REG_ANC_STAT         0xf005
 #define WM2000_REG_IF_CTL           0xf006
+#define WM2000_REG_ANA_MIC_CTL      0xf028
+#define WM2000_REG_SPK_CTL          0xf034
 
 /* SPEECH_CLARITY */
 #define WM2000_SPEECH_CLARITY   0x01
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index ddc98f02ecbd..57ba315d0c84 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -1565,7 +1565,7 @@ static int wm2200_probe(struct snd_soc_codec *codec)
 		return ret;
 	}
 
-	ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 2);
+	ret = snd_soc_add_codec_controls(codec, wm_adsp1_fw_controls, 2);
 	if (ret != 0)
 		return ret;
 
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index 15bc31f1abb1..e895d3939eef 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -36,9 +36,6 @@
 struct wm5102_priv {
 	struct arizona_priv core;
 	struct arizona_fll fll[2];
-
-	unsigned int spk_ena:2;
-	unsigned int spk_ena_pending:1;
 };
 
 static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
@@ -615,6 +612,26 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
 	return 0;
 }
 
+static const char *wm5102_osr_text[] = {
+	"Low power", "Normal", "High performance",
+};
+
+static const unsigned int wm5102_osr_val[] = {
+	0x0, 0x3, 0x5,
+};
+
+static const struct soc_enum wm5102_hpout_osr[] = {
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
+			      ARIZONA_OUT1_OSR_SHIFT, 0x7, 3,
+			      wm5102_osr_text, wm5102_osr_val),
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L,
+			      ARIZONA_OUT2_OSR_SHIFT, 0x7, 3,
+			      wm5102_osr_text, wm5102_osr_val),
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
+			      ARIZONA_OUT3_OSR_SHIFT, 0x7, 3,
+			      wm5102_osr_text, wm5102_osr_val),
+};
+
 #define WM5102_NG_SRC(name, base) \
 	SOC_SINGLE(name " NG HPOUT1L Switch",  base, 0, 1, 0), \
 	SOC_SINGLE(name " NG HPOUT1R Switch",  base, 1, 1, 0), \
@@ -745,6 +762,9 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
 SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
 SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
 
+SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
+SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
+
 ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE),
 
@@ -761,6 +781,8 @@ ARIZONA_MIXER_CONTROLS("SPKOUTR", ARIZONA_OUT4RMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("SPKDAT1R", ARIZONA_OUT5RMIX_INPUT_1_SOURCE),
 
+SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L,
+	   ARIZONA_OUT4_OSR_SHIFT, 1, 0),
 SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L,
 	   ARIZONA_OUT5_OSR_SHIFT, 1, 0),
 
@@ -790,6 +812,10 @@ SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L,
 		 ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT,
 		 0xbf, 0, digital_tlv),
 
+SOC_VALUE_ENUM("HPOUT1 OSR", wm5102_hpout_osr[0]),
+SOC_VALUE_ENUM("HPOUT2 OSR", wm5102_hpout_osr[1]),
+SOC_VALUE_ENUM("HPOUT3 OSR", wm5102_hpout_osr[2]),
+
 SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
 SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
 
@@ -828,47 +854,6 @@ ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
 };
 
-static int wm5102_spk_ev(struct snd_soc_dapm_widget *w,
-			 struct snd_kcontrol *kcontrol,
-			 int event)
-{
-	struct snd_soc_codec *codec = w->codec;
-	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
-	struct wm5102_priv *wm5102 = snd_soc_codec_get_drvdata(codec);
-
-	if (arizona->rev < 1)
-		return 0;
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		if (!wm5102->spk_ena) {
-			snd_soc_write(codec, 0x4f5, 0x25a);
-			wm5102->spk_ena_pending = true;
-		}
-		break;
-	case SND_SOC_DAPM_POST_PMU:
-		if (wm5102->spk_ena_pending) {
-			msleep(75);
-			snd_soc_write(codec, 0x4f5, 0xda);
-			wm5102->spk_ena_pending = false;
-			wm5102->spk_ena++;
-		}
-		break;
-	case SND_SOC_DAPM_PRE_PMD:
-		wm5102->spk_ena--;
-		if (!wm5102->spk_ena)
-			snd_soc_write(codec, 0x4f5, 0x25a);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		if (!wm5102->spk_ena)
-			snd_soc_write(codec, 0x4f5, 0x0da);
-		break;
-	}
-
-	return 0;
-}
-
-
 ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE);
@@ -984,22 +969,28 @@ SND_SOC_DAPM_INPUT("IN3R"),
 
 SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
 		   0, NULL, 0, arizona_in_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
 		   0, NULL, 0, arizona_in_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
 		   0, NULL, 0, arizona_in_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT,
 		   0, NULL, 0, arizona_in_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT,
 		   0, NULL, 0, arizona_in_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT,
 		   0, NULL, 0, arizona_in_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 
 SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1,
 		    ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
@@ -1146,12 +1137,6 @@ SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1,
 SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
 		   ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
 		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1,
-		   ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, wm5102_spk_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1,
-		   ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, wm5102_spk_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
 		   ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
 		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
@@ -1494,6 +1479,12 @@ static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 		return arizona_set_fll(&wm5102->fll[0], source, Fref, Fout);
 	case WM5102_FLL2:
 		return arizona_set_fll(&wm5102->fll[1], source, Fref, Fout);
+	case WM5102_FLL1_REFCLK:
+		return arizona_set_fll_refclk(&wm5102->fll[0], source, Fref,
+					      Fout);
+	case WM5102_FLL2_REFCLK:
+		return arizona_set_fll_refclk(&wm5102->fll[1], source, Fref,
+					      Fout);
 	default:
 		return -EINVAL;
 	}
@@ -1581,10 +1572,12 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
 	if (ret != 0)
 		return ret;
 
-	ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 1);
+	ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 2);
 	if (ret != 0)
 		return ret;
 
+	arizona_init_spk(codec);
+
 	snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
 
 	priv->core.arizona->dapm = &codec->dapm;
@@ -1604,13 +1597,6 @@ static int wm5102_codec_remove(struct snd_soc_codec *codec)
 #define WM5102_DIG_VU 0x0200
 
 static unsigned int wm5102_digital_vu[] = {
-	ARIZONA_ADC_DIGITAL_VOLUME_1L,
-	ARIZONA_ADC_DIGITAL_VOLUME_1R,
-	ARIZONA_ADC_DIGITAL_VOLUME_2L,
-	ARIZONA_ADC_DIGITAL_VOLUME_2R,
-	ARIZONA_ADC_DIGITAL_VOLUME_3L,
-	ARIZONA_ADC_DIGITAL_VOLUME_3R,
-
 	ARIZONA_DAC_DIGITAL_VOLUME_1L,
 	ARIZONA_DAC_DIGITAL_VOLUME_1R,
 	ARIZONA_DAC_DIGITAL_VOLUME_2L,
@@ -1653,6 +1639,7 @@ static int wm5102_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, wm5102);
 
 	wm5102->core.arizona = arizona;
+	wm5102->core.num_inputs = 6;
 
 	wm5102->core.adsp[0].part = "wm5102";
 	wm5102->core.adsp[0].num = 1;
@@ -1677,6 +1664,12 @@ static int wm5102_probe(struct platform_device *pdev)
 			 ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,
 			 &wm5102->fll[1]);
 
+	/* SR2 fixed at 8kHz, SR3 fixed at 16kHz */
+	regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2,
+			   ARIZONA_SAMPLE_RATE_2_MASK, 0x11);
+	regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3,
+			   ARIZONA_SAMPLE_RATE_3_MASK, 0x12);
+
 	for (i = 0; i < ARRAY_SIZE(wm5102_dai); i++)
 		arizona_init_dai(&wm5102->core, i);
 
diff --git a/sound/soc/codecs/wm5102.h b/sound/soc/codecs/wm5102.h
index d30477f3070c..adb38040f661 100644
--- a/sound/soc/codecs/wm5102.h
+++ b/sound/soc/codecs/wm5102.h
@@ -15,7 +15,9 @@
 
 #include "arizona.h"
 
-#define WM5102_FLL1 1
-#define WM5102_FLL2 2
+#define WM5102_FLL1        1
+#define WM5102_FLL2        2
+#define WM5102_FLL1_REFCLK 3
+#define WM5102_FLL2_REFCLK 4
 
 #endif
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index 7841b42a819c..731884e04776 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -416,28 +416,36 @@ SND_SOC_DAPM_INPUT("IN4R"),
 
 SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
 		   0, NULL, 0, arizona_in_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
 		   0, NULL, 0, arizona_in_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
 		   0, NULL, 0, arizona_in_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT,
 		   0, NULL, 0, arizona_in_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT,
 		   0, NULL, 0, arizona_in_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT,
 		   0, NULL, 0, arizona_in_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN4L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4L_ENA_SHIFT,
 		   0, NULL, 0, arizona_in_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN4R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4R_ENA_SHIFT,
 		   0, NULL, 0, arizona_in_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 
 SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1,
 		    ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
@@ -569,12 +577,6 @@ SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
 SND_SOC_DAPM_PGA_E("OUT3R", ARIZONA_OUTPUT_ENABLES_1,
 		   ARIZONA_OUT3R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
 		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1,
-		   ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1,
-		   ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
 		   ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
 		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
@@ -880,6 +882,12 @@ static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 		return arizona_set_fll(&wm5110->fll[0], source, Fref, Fout);
 	case WM5110_FLL2:
 		return arizona_set_fll(&wm5110->fll[1], source, Fref, Fout);
+	case WM5110_FLL1_REFCLK:
+		return arizona_set_fll_refclk(&wm5110->fll[0], source, Fref,
+					      Fout);
+	case WM5110_FLL2_REFCLK:
+		return arizona_set_fll_refclk(&wm5110->fll[1], source, Fref,
+					      Fout);
 	default:
 		return -EINVAL;
 	}
@@ -987,15 +995,6 @@ static int wm5110_codec_remove(struct snd_soc_codec *codec)
 #define WM5110_DIG_VU 0x0200
 
 static unsigned int wm5110_digital_vu[] = {
-	ARIZONA_ADC_DIGITAL_VOLUME_1L,
-	ARIZONA_ADC_DIGITAL_VOLUME_1R,
-	ARIZONA_ADC_DIGITAL_VOLUME_2L,
-	ARIZONA_ADC_DIGITAL_VOLUME_2R,
-	ARIZONA_ADC_DIGITAL_VOLUME_3L,
-	ARIZONA_ADC_DIGITAL_VOLUME_3R,
-	ARIZONA_ADC_DIGITAL_VOLUME_4L,
-	ARIZONA_ADC_DIGITAL_VOLUME_4R,
-
 	ARIZONA_DAC_DIGITAL_VOLUME_1L,
 	ARIZONA_DAC_DIGITAL_VOLUME_1R,
 	ARIZONA_DAC_DIGITAL_VOLUME_2L,
@@ -1040,6 +1039,7 @@ static int wm5110_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, wm5110);
 
 	wm5110->core.arizona = arizona;
+	wm5110->core.num_inputs = 8;
 
 	for (i = 0; i < ARRAY_SIZE(wm5110->fll); i++)
 		wm5110->fll[i].vco_mult = 3;
diff --git a/sound/soc/codecs/wm5110.h b/sound/soc/codecs/wm5110.h
index 75e9351ccab0..e6c0cd4235c5 100644
--- a/sound/soc/codecs/wm5110.h
+++ b/sound/soc/codecs/wm5110.h
@@ -15,7 +15,9 @@
 
 #include "arizona.h"
 
-#define WM5110_FLL1 1
-#define WM5110_FLL2 2
+#define WM5110_FLL1        1
+#define WM5110_FLL2        2
+#define WM5110_FLL1_REFCLK 3
+#define WM5110_FLL2_REFCLK 4
 
 #endif
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index f8a31ad0b203..9d88437cdcd1 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -478,6 +478,8 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
 /* ALSA can only do steps of .01dB */
 static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
 
+static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0);
+
 static const DECLARE_TLV_DB_SCALE(digital_sidetone_tlv, -3600, 300, 0);
 static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
 
@@ -698,6 +700,8 @@ SOC_ENUM("DAC Mute Mode", mute_mode),
 SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0),
 SOC_ENUM("DAC Companding Mode", dac_companding),
 SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0),
+SOC_SINGLE_TLV("DAC Boost Volume", WM8903_AUDIO_INTERFACE_0, 9, 3, 0,
+	       dac_boost_tlv),
 SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0,
 		    wm8903_get_deemph, wm8903_put_deemph),
 
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index a64b93425ae3..0a4ffdd1d2a7 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -204,6 +204,7 @@ static const DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 50, 0);
 static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1);
 static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0);
 static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, -1200, 300, 1);
 
 static const struct snd_kcontrol_new wm8960_snd_controls[] = {
 SOC_DOUBLE_R_TLV("Capture Volume", WM8960_LINVOL, WM8960_RINVOL,
@@ -213,6 +214,15 @@ SOC_DOUBLE_R("Capture Volume ZC Switch", WM8960_LINVOL, WM8960_RINVOL,
 SOC_DOUBLE_R("Capture Switch", WM8960_LINVOL, WM8960_RINVOL,
 	7, 1, 0),
 
+SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT3 Volume",
+	       WM8960_INBMIX1, 4, 7, 0, boost_tlv),
+SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT2 Volume",
+	       WM8960_INBMIX1, 1, 7, 0, boost_tlv),
+SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT3 Volume",
+	       WM8960_INBMIX2, 4, 7, 0, boost_tlv),
+SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT2 Volume",
+	       WM8960_INBMIX2, 1, 7, 0, boost_tlv),
+
 SOC_DOUBLE_R_TLV("Playback Volume", WM8960_LDAC, WM8960_RDAC,
 		 0, 255, 0, dac_tlv),
 
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index c9bd445c4976..14094f558e03 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -2209,7 +2209,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
 				vmid_reference(codec);
 				break;
 			case WM8958:
-				if (wm8994->revision < 1)
+				if (control->revision < 1)
 					vmid_reference(codec);
 				break;
 			default:
@@ -2244,7 +2244,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
 				vmid_dereference(codec);
 				break;
 			case WM8958:
-				if (wm8994->revision < 1)
+				if (control->revision < 1)
 					vmid_dereference(codec);
 				break;
 			default:
@@ -2268,10 +2268,26 @@ out:
 	 */
 	if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
 		dev_dbg(codec->dev, "Configuring AIFs for 128fs\n");
+
+		wm8994->aifdiv[0] = snd_soc_read(codec, WM8994_AIF1_RATE)
+			& WM8994_AIF1CLK_RATE_MASK;
+		wm8994->aifdiv[1] = snd_soc_read(codec, WM8994_AIF2_RATE)
+			& WM8994_AIF1CLK_RATE_MASK;
+
 		snd_soc_update_bits(codec, WM8994_AIF1_RATE,
 				    WM8994_AIF1CLK_RATE_MASK, 0x1);
 		snd_soc_update_bits(codec, WM8994_AIF2_RATE,
 				    WM8994_AIF2CLK_RATE_MASK, 0x1);
+	} else if (wm8994->aifdiv[0]) {
+		snd_soc_update_bits(codec, WM8994_AIF1_RATE,
+				    WM8994_AIF1CLK_RATE_MASK,
+				    wm8994->aifdiv[0]);
+		snd_soc_update_bits(codec, WM8994_AIF2_RATE,
+				    WM8994_AIF2CLK_RATE_MASK,
+				    wm8994->aifdiv[1]);
+
+		wm8994->aifdiv[0] = 0;
+		wm8994->aifdiv[1] = 0;
 	}
 
 	return 0;
@@ -2368,10 +2384,26 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
 	 */
 	if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
 		dev_dbg(codec->dev, "Configuring AIFs for 128fs\n");
+
+		wm8994->aifdiv[0] = snd_soc_read(codec, WM8994_AIF1_RATE)
+			& WM8994_AIF1CLK_RATE_MASK;
+		wm8994->aifdiv[1] = snd_soc_read(codec, WM8994_AIF2_RATE)
+			& WM8994_AIF1CLK_RATE_MASK;
+
 		snd_soc_update_bits(codec, WM8994_AIF1_RATE,
 				    WM8994_AIF1CLK_RATE_MASK, 0x1);
 		snd_soc_update_bits(codec, WM8994_AIF2_RATE,
 				    WM8994_AIF2CLK_RATE_MASK, 0x1);
+	} else if (wm8994->aifdiv[0]) {
+		snd_soc_update_bits(codec, WM8994_AIF1_RATE,
+				    WM8994_AIF1CLK_RATE_MASK,
+				    wm8994->aifdiv[0]);
+		snd_soc_update_bits(codec, WM8994_AIF2_RATE,
+				    WM8994_AIF2CLK_RATE_MASK,
+				    wm8994->aifdiv[1]);
+
+		wm8994->aifdiv[0] = 0;
+		wm8994->aifdiv[1] = 0;
 	}
 
 	return 0;
@@ -2411,7 +2443,7 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
 		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
 			switch (control->type) {
 			case WM8958:
-				if (wm8994->revision == 0) {
+				if (control->revision == 0) {
 					/* Optimise performance for rev A */
 					snd_soc_update_bits(codec,
 							    WM8958_CHARGE_PUMP_2,
@@ -2656,6 +2688,8 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
 {
 	struct snd_soc_codec *codec = dai->codec;
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994 *control = wm8994->wm8994;
+	struct wm8994_pdata *pdata = &control->pdata;
 	int aif1_reg;
 	int aif2_reg;
 	int bclk_reg;
@@ -2723,7 +2757,14 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	wm8994->channels[id] = params_channels(params);
-	switch (params_channels(params)) {
+	if (pdata->max_channels_clocked[id] &&
+	    wm8994->channels[id] > pdata->max_channels_clocked[id]) {
+		dev_dbg(dai->dev, "Constraining channels to %d from %d\n",
+			pdata->max_channels_clocked[id], wm8994->channels[id]);
+		wm8994->channels[id] = pdata->max_channels_clocked[id];
+	}
+
+	switch (wm8994->channels[id]) {
 	case 1:
 	case 2:
 		bclk_rate *= 2;
@@ -2745,7 +2786,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
 	dev_dbg(dai->dev, "AIF%dCLK is %dHz, target BCLK %dHz\n",
 		dai->id, wm8994->aifclk[id], bclk_rate);
 
-	if (params_channels(params) == 1 &&
+	if (wm8994->channels[id] == 1 &&
 	    (snd_soc_read(codec, aif1_reg) & 0x18) == 0x18)
 		aif2 |= WM8994_AIF1_MONO;
 
@@ -3053,7 +3094,7 @@ static int wm8994_codec_resume(struct snd_soc_codec *codec)
 	int i, ret;
 	unsigned int val, mask;
 
-	if (wm8994->revision < 4) {
+	if (control->revision < 4) {
 		/* force a HW read */
 		ret = regmap_read(control->regmap,
 				  WM8994_POWER_MANAGEMENT_5, &val);
@@ -3870,7 +3911,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 	codec->dapm.idle_bias_off = 1;
 
 	/* Set revision-specific configuration */
-	wm8994->revision = snd_soc_read(codec, WM8994_CHIP_REVISION);
 	switch (control->type) {
 	case WM8994:
 		/* Single ended line outputs should have VMID on. */
@@ -3878,7 +3918,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 		    !control->pdata.lineout2_diff)
 			codec->dapm.idle_bias_off = 0;
 
-		switch (wm8994->revision) {
+		switch (control->revision) {
 		case 2:
 		case 3:
 			wm8994->hubs.dcs_codes_l = -5;
@@ -3897,7 +3937,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 		wm8994->hubs.dcs_readback_mode = 1;
 		wm8994->hubs.hp_startup_mode = 1;
 
-		switch (wm8994->revision) {
+		switch (control->revision) {
 		case 0:
 			break;
 		default:
@@ -4000,7 +4040,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 
 	switch (control->type) {
 	case WM1811:
-		if (control->cust_id > 1 || wm8994->revision > 1) {
+		if (control->cust_id > 1 || control->revision > 1) {
 			ret = wm8994_request_irq(wm8994->wm8994,
 						 WM8994_IRQ_GPIO(6),
 						 wm1811_jackdet_irq, "JACKDET",
@@ -4114,7 +4154,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 	case WM8994:
 		snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets,
 					  ARRAY_SIZE(wm8994_specific_dapm_widgets));
-		if (wm8994->revision < 4) {
+		if (control->revision < 4) {
 			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,
@@ -4135,7 +4175,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 				     ARRAY_SIZE(wm8958_snd_controls));
 		snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
 					  ARRAY_SIZE(wm8958_dapm_widgets));
-		if (wm8994->revision < 1) {
+		if (control->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,
@@ -4174,7 +4214,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 		snd_soc_dapm_add_routes(dapm, wm8994_intercon,
 					ARRAY_SIZE(wm8994_intercon));
 
-		if (wm8994->revision < 4) {
+		if (control->revision < 4) {
 			snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon,
 						ARRAY_SIZE(wm8994_revd_intercon));
 			snd_soc_dapm_add_routes(dapm, wm8994_lateclk_revd_intercon,
@@ -4185,7 +4225,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 		}
 		break;
 	case WM8958:
-		if (wm8994->revision < 1) {
+		if (control->revision < 1) {
 			snd_soc_dapm_add_routes(dapm, wm8994_intercon,
 						ARRAY_SIZE(wm8994_intercon));
 			snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon,
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index 45f192702024..55ddf4d57d9b 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -79,6 +79,7 @@ struct wm8994_priv {
 	int sysclk_rate[2];
 	int mclk[2];
 	int aifclk[2];
+	int aifdiv[2];
 	int channels[2];
 	struct wm8994_fll_config fll[2], fll_suspend[2];
 	struct completion fll_locked[2];
@@ -146,8 +147,6 @@ struct wm8994_priv {
 	wm1811_mic_id_cb mic_id_cb;
 	void *mic_id_cb_data;
 
-	int revision;
-
 	unsigned int aif1clk_enable:1;
 	unsigned int aif2clk_enable:1;
 
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 9af1bddc4c62..3470b649c0b2 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -31,6 +31,7 @@
 
 #include <linux/mfd/arizona/registers.h>
 
+#include "arizona.h"
 #include "wm_adsp.h"
 
 #define adsp_crit(_dsp, fmt, ...) \
@@ -193,17 +194,25 @@ static void wm_adsp_buf_free(struct list_head *list)
 
 #define WM_ADSP_NUM_FW 4
 
+#define WM_ADSP_FW_MBC_VSS 0
+#define WM_ADSP_FW_TX      1
+#define WM_ADSP_FW_TX_SPK  2
+#define WM_ADSP_FW_RX_ANC  3
+
 static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
-	"MBC/VSS", "Tx", "Tx Speaker", "Rx ANC"
+	[WM_ADSP_FW_MBC_VSS] = "MBC/VSS",
+	[WM_ADSP_FW_TX] =      "Tx",
+	[WM_ADSP_FW_TX_SPK] =  "Tx Speaker",
+	[WM_ADSP_FW_RX_ANC] =  "Rx ANC",
 };
 
 static struct {
 	const char *file;
 } wm_adsp_fw[WM_ADSP_NUM_FW] = {
-	{ .file = "mbc-vss" },
-	{ .file = "tx" },
-	{ .file = "tx-spk" },
-	{ .file = "rx-anc" },
+	[WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" },
+	[WM_ADSP_FW_TX] =      { .file = "tx" },
+	[WM_ADSP_FW_TX_SPK] =  { .file = "tx-spk" },
+	[WM_ADSP_FW_RX_ANC] =  { .file = "rx-anc" },
 };
 
 static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
@@ -246,17 +255,52 @@ static const struct soc_enum wm_adsp_fw_enum[] = {
 	SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 };
 
-const struct snd_kcontrol_new wm_adsp_fw_controls[] = {
+const struct snd_kcontrol_new wm_adsp1_fw_controls[] = {
+	SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
+		     wm_adsp_fw_get, wm_adsp_fw_put),
+	SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
+		     wm_adsp_fw_get, wm_adsp_fw_put),
+	SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
+		     wm_adsp_fw_get, wm_adsp_fw_put),
+};
+EXPORT_SYMBOL_GPL(wm_adsp1_fw_controls);
+
+#if IS_ENABLED(CONFIG_SND_SOC_ARIZONA)
+static const struct soc_enum wm_adsp2_rate_enum[] = {
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1,
+			      ARIZONA_DSP1_RATE_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE,
+			      arizona_rate_text, arizona_rate_val),
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1,
+			      ARIZONA_DSP1_RATE_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE,
+			      arizona_rate_text, arizona_rate_val),
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
+			      ARIZONA_DSP1_RATE_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE,
+			      arizona_rate_text, arizona_rate_val),
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
+			      ARIZONA_DSP1_RATE_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE,
+			      arizona_rate_text, arizona_rate_val),
+};
+
+const struct snd_kcontrol_new wm_adsp2_fw_controls[] = {
 	SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
 		     wm_adsp_fw_get, wm_adsp_fw_put),
+	SOC_ENUM("DSP1 Rate", wm_adsp2_rate_enum[0]),
 	SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
 		     wm_adsp_fw_get, wm_adsp_fw_put),
+	SOC_ENUM("DSP2 Rate", wm_adsp2_rate_enum[1]),
 	SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
 		     wm_adsp_fw_get, wm_adsp_fw_put),
+	SOC_ENUM("DSP3 Rate", wm_adsp2_rate_enum[2]),
 	SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3],
 		     wm_adsp_fw_get, wm_adsp_fw_put),
+	SOC_ENUM("DSP4 Rate", wm_adsp2_rate_enum[3]),
 };
-EXPORT_SYMBOL_GPL(wm_adsp_fw_controls);
+EXPORT_SYMBOL_GPL(wm_adsp2_fw_controls);
+#endif
 
 static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
 							int type)
@@ -549,13 +593,30 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
 		buf_size = sizeof(adsp1_id);
 
 		algs = be32_to_cpu(adsp1_id.algs);
+		dsp->fw_id = be32_to_cpu(adsp1_id.fw.id);
 		adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
-			  be32_to_cpu(adsp1_id.fw.id),
+			  dsp->fw_id,
 			  (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
 			  (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
 			  be32_to_cpu(adsp1_id.fw.ver) & 0xff,
 			  algs);
 
+		region = kzalloc(sizeof(*region), GFP_KERNEL);
+		if (!region)
+			return -ENOMEM;
+		region->type = WMFW_ADSP1_ZM;
+		region->alg = be32_to_cpu(adsp1_id.fw.id);
+		region->base = be32_to_cpu(adsp1_id.zm);
+		list_add_tail(&region->list, &dsp->alg_regions);
+
+		region = kzalloc(sizeof(*region), GFP_KERNEL);
+		if (!region)
+			return -ENOMEM;
+		region->type = WMFW_ADSP1_DM;
+		region->alg = be32_to_cpu(adsp1_id.fw.id);
+		region->base = be32_to_cpu(adsp1_id.dm);
+		list_add_tail(&region->list, &dsp->alg_regions);
+
 		pos = sizeof(adsp1_id) / 2;
 		term = pos + ((sizeof(*adsp1_alg) * algs) / 2);
 		break;
@@ -573,13 +634,38 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
 		buf_size = sizeof(adsp2_id);
 
 		algs = be32_to_cpu(adsp2_id.algs);
+		dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
 		adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
-			  be32_to_cpu(adsp2_id.fw.id),
+			  dsp->fw_id,
 			  (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
 			  (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
 			  be32_to_cpu(adsp2_id.fw.ver) & 0xff,
 			  algs);
 
+		region = kzalloc(sizeof(*region), GFP_KERNEL);
+		if (!region)
+			return -ENOMEM;
+		region->type = WMFW_ADSP2_XM;
+		region->alg = be32_to_cpu(adsp2_id.fw.id);
+		region->base = be32_to_cpu(adsp2_id.xm);
+		list_add_tail(&region->list, &dsp->alg_regions);
+
+		region = kzalloc(sizeof(*region), GFP_KERNEL);
+		if (!region)
+			return -ENOMEM;
+		region->type = WMFW_ADSP2_YM;
+		region->alg = be32_to_cpu(adsp2_id.fw.id);
+		region->base = be32_to_cpu(adsp2_id.ym);
+		list_add_tail(&region->list, &dsp->alg_regions);
+
+		region = kzalloc(sizeof(*region), GFP_KERNEL);
+		if (!region)
+			return -ENOMEM;
+		region->type = WMFW_ADSP2_ZM;
+		region->alg = be32_to_cpu(adsp2_id.fw.id);
+		region->base = be32_to_cpu(adsp2_id.zm);
+		list_add_tail(&region->list, &dsp->alg_regions);
+
 		pos = sizeof(adsp2_id) / 2;
 		term = pos + ((sizeof(*adsp2_alg) * algs) / 2);
 		break;
@@ -781,8 +867,24 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
 		case (WMFW_INFO_TEXT << 8):
 			break;
 		case (WMFW_ABSOLUTE << 8):
-			region_name = "register";
-			reg = offset;
+			/*
+			 * Old files may use this for global
+			 * coefficients.
+			 */
+			if (le32_to_cpu(blk->id) == dsp->fw_id &&
+			    offset == 0) {
+				region_name = "global coefficients";
+				mem = wm_adsp_find_region(dsp, type);
+				if (!mem) {
+					adsp_err(dsp, "No ZM\n");
+					break;
+				}
+				reg = wm_adsp_region_to_reg(mem, 0);
+
+			} else {
+				region_name = "register";
+				reg = offset;
+			}
 			break;
 
 		case WMFW_ADSP1_DM:
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index cb8871a3ec00..fea514627526 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -46,6 +46,8 @@ struct wm_adsp {
 
 	struct list_head alg_regions;
 
+	int fw_id;
+
 	const struct wm_adsp_region *mem;
 	int num_mems;
 
@@ -65,7 +67,8 @@ struct wm_adsp {
 	.shift = num, .event = wm_adsp2_event, \
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
 
-extern const struct snd_kcontrol_new wm_adsp_fw_controls[];
+extern const struct snd_kcontrol_new wm_adsp1_fw_controls[];
+extern const struct snd_kcontrol_new wm_adsp2_fw_controls[];
 
 int wm_adsp1_init(struct wm_adsp *adsp);
 int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs);
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index 867ae97ddcec..f5d81b948759 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -199,11 +199,12 @@ static void wm_hubs_dcs_cache_set(struct snd_soc_codec *codec, u16 dcs_cfg)
 	list_add_tail(&cache->list, &hubs->dcs_cache);
 }
 
-static void wm_hubs_read_dc_servo(struct snd_soc_codec *codec,
+static int wm_hubs_read_dc_servo(struct snd_soc_codec *codec,
 				  u16 *reg_l, u16 *reg_r)
 {
 	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
 	u16 dcs_reg, reg;
+	int ret = 0;
 
 	switch (hubs->dcs_readback_mode) {
 	case 2:
@@ -236,8 +237,9 @@ static void wm_hubs_read_dc_servo(struct snd_soc_codec *codec,
 		break;
 	default:
 		WARN(1, "Unknown DCS readback method\n");
-		return;
+		ret = -1;
 	}
+	return ret;
 }
 
 /*
@@ -286,7 +288,8 @@ static void enable_dc_servo(struct snd_soc_codec *codec)
 				  WM8993_DCS_TRIG_STARTUP_1);
 	}
 
-	wm_hubs_read_dc_servo(codec, &reg_l, &reg_r);
+	if (wm_hubs_read_dc_servo(codec, &reg_l, &reg_r) < 0)
+		return;
 
 	dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
 
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index 821831207180..ebe82947bab3 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -645,6 +645,10 @@ static struct snd_soc_dai_driver davinci_i2s_dai = {
 
 };
 
+static const struct snd_soc_component_driver davinci_i2s_component = {
+	.name		= "davinci-i2s",
+};
+
 static int davinci_i2s_probe(struct platform_device *pdev)
 {
 	struct snd_platform_data *pdata = pdev->dev.platform_data;
@@ -727,20 +731,21 @@ static int davinci_i2s_probe(struct platform_device *pdev)
 
 	dev_set_drvdata(&pdev->dev, dev);
 
-	ret = snd_soc_register_dai(&pdev->dev, &davinci_i2s_dai);
+	ret = snd_soc_register_component(&pdev->dev, &davinci_i2s_component,
+					 &davinci_i2s_dai, 1);
 	if (ret != 0)
 		goto err_release_clk;
 
 	ret = davinci_soc_platform_register(&pdev->dev);
 	if (ret) {
 		dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
-		goto err_unregister_dai;
+		goto err_unregister_component;
 	}
 
 	return 0;
 
-err_unregister_dai:
-	snd_soc_unregister_dai(&pdev->dev);
+err_unregister_component:
+	snd_soc_unregister_component(&pdev->dev);
 err_release_clk:
 	clk_disable(dev->clk);
 	clk_put(dev->clk);
@@ -751,7 +756,7 @@ static int davinci_i2s_remove(struct platform_device *pdev)
 {
 	struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev);
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	davinci_soc_platform_unregister(&pdev->dev);
 
 	clk_disable(dev->clk);
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index 9321e5c9d8c1..8b85049daab0 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -235,6 +235,8 @@
 #define DISMOD		(val)(val<<2)
 #define TXSTATE		BIT(4)
 #define RXSTATE		BIT(5)
+#define SRMOD_MASK	3
+#define SRMOD_INACTIVE	0
 
 /*
  * DAVINCI_MCASP_LBCTL_REG - Loop Back Control Register Bits
@@ -634,35 +636,43 @@ static int davinci_config_channel_size(struct davinci_audio_dev *dev,
 	 * callback, take it into account here. That allows us to for example
 	 * send 32 bits per channel to the codec, while only 16 of them carry
 	 * audio payload.
-	 * The clock ratio is given for a full period of data (both left and
-	 * right channels), so it has to be divided by 2.
+	 * The clock ratio is given for a full period of data (for I2S format
+	 * both left and right channels), so it has to be divided by number of
+	 * tdm-slots (for I2S - divided by 2).
 	 */
 	if (dev->bclk_lrclk_ratio)
-		word_length = dev->bclk_lrclk_ratio / 2;
+		word_length = dev->bclk_lrclk_ratio / dev->tdm_slots;
 
 	/* mapping of the XSSZ bit-field as described in the datasheet */
 	fmt = (word_length >> 1) - 1;
 
-	mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
-					RXSSZ(fmt), RXSSZ(0x0F));
-	mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
-					TXSSZ(fmt), TXSSZ(0x0F));
-	mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, TXROT(rotate),
-							TXROT(7));
-	mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, RXROT(rotate),
-							RXROT(7));
+	if (dev->op_mode != DAVINCI_MCASP_DIT_MODE) {
+		mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
+				RXSSZ(fmt), RXSSZ(0x0F));
+		mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
+				TXSSZ(fmt), TXSSZ(0x0F));
+		mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
+				TXROT(rotate), TXROT(7));
+		mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
+				RXROT(rotate), RXROT(7));
+		mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG,
+				mask);
+	}
+
 	mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, mask);
-	mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG, mask);
 
 	return 0;
 }
 
-static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream)
+static int davinci_hw_common_param(struct davinci_audio_dev *dev, int stream,
+				    int channels)
 {
 	int i;
 	u8 tx_ser = 0;
 	u8 rx_ser = 0;
-
+	u8 ser;
+	u8 slots = dev->tdm_slots;
+	u8 max_active_serializers = (channels + slots - 1) / slots;
 	/* Default configuration */
 	mcasp_set_bits(dev->base + DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
 
@@ -682,17 +692,33 @@ static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream)
 	for (i = 0; i < dev->num_serializer; i++) {
 		mcasp_set_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i),
 					dev->serial_dir[i]);
-		if (dev->serial_dir[i] == TX_MODE) {
+		if (dev->serial_dir[i] == TX_MODE &&
+					tx_ser < max_active_serializers) {
 			mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
 					AXR(i));
 			tx_ser++;
-		} else if (dev->serial_dir[i] == RX_MODE) {
+		} else if (dev->serial_dir[i] == RX_MODE &&
+					rx_ser < max_active_serializers) {
 			mcasp_clr_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
 					AXR(i));
 			rx_ser++;
+		} else {
+			mcasp_mod_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i),
+					SRMOD_INACTIVE, SRMOD_MASK);
 		}
 	}
 
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ser = tx_ser;
+	else
+		ser = rx_ser;
+
+	if (ser < max_active_serializers) {
+		dev_warn(dev->dev, "stream has more channels (%d) than are "
+			"enabled in mcasp (%d)\n", channels, ser * slots);
+		return -EINVAL;
+	}
+
 	if (dev->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		if (dev->txnumevt * tx_ser > 64)
 			dev->txnumevt = 1;
@@ -729,6 +755,8 @@ static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream)
 				((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK);
 		}
 	}
+
+	return 0;
 }
 
 static void davinci_hw_param(struct davinci_audio_dev *dev, int stream)
@@ -772,12 +800,6 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream)
 /* S/PDIF */
 static void davinci_hw_dit_param(struct davinci_audio_dev *dev)
 {
-	/* Set the PDIR for Serialiser as output */
-	mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AFSX);
-
-	/* TXMASK for 24 bits */
-	mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, 0x00FFFFFF);
-
 	/* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
 	   and LSB first */
 	mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
@@ -812,12 +834,21 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
 					&dev->dma_params[substream->stream];
 	int word_length;
 	u8 fifo_level;
+	u8 slots = dev->tdm_slots;
+	u8 active_serializers;
+	int channels;
+	struct snd_interval *pcm_channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+	channels = pcm_channels->min;
+
+	active_serializers = (channels + slots - 1) / slots;
 
-	davinci_hw_common_param(dev, substream->stream);
+	if (davinci_hw_common_param(dev, substream->stream, channels) == -EINVAL)
+		return -EINVAL;
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		fifo_level = dev->txnumevt;
+		fifo_level = dev->txnumevt * active_serializers;
 	else
-		fifo_level = dev->rxnumevt;
+		fifo_level = dev->rxnumevt * active_serializers;
 
 	if (dev->op_mode == DAVINCI_MCASP_DIT_MODE)
 		davinci_hw_dit_param(dev);
@@ -936,13 +967,13 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
 		.name		= "davinci-mcasp.0",
 		.playback	= {
 			.channels_min	= 2,
-			.channels_max 	= 2,
+			.channels_max	= 32 * 16,
 			.rates 		= DAVINCI_MCASP_RATES,
 			.formats	= DAVINCI_MCASP_PCM_FMTS,
 		},
 		.capture 	= {
 			.channels_min 	= 2,
-			.channels_max 	= 2,
+			.channels_max	= 32 * 16,
 			.rates 		= DAVINCI_MCASP_RATES,
 			.formats	= DAVINCI_MCASP_PCM_FMTS,
 		},
@@ -962,6 +993,10 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
 
 };
 
+static const struct snd_soc_component_driver davinci_mcasp_component = {
+	.name		= "davinci-mcasp",
+};
+
 static const struct of_device_id mcasp_dt_ids[] = {
 	{
 		.compatible = "ti,dm646x-mcasp-audio",
@@ -1015,8 +1050,16 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
 		pdata->op_mode = val;
 
 	ret = of_property_read_u32(np, "tdm-slots", &val);
-	if (ret >= 0)
+	if (ret >= 0) {
+		if (val < 2 || val > 32) {
+			dev_err(&pdev->dev,
+				"tdm-slots must be in rage [2-32]\n");
+			ret = -EINVAL;
+			goto nodata;
+		}
+
 		pdata->tdm_slots = val;
+	}
 
 	ret = of_property_read_u32(np, "num-serializer", &val);
 	if (ret >= 0)
@@ -1170,7 +1213,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 
 	dma_data->channel = res->start;
 	dev_set_drvdata(&pdev->dev, dev);
-	ret = snd_soc_register_dai(&pdev->dev, &davinci_mcasp_dai[pdata->op_mode]);
+	ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
+					 &davinci_mcasp_dai[pdata->op_mode], 1);
 
 	if (ret != 0)
 		goto err_release_clk;
@@ -1178,13 +1222,13 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 	ret = davinci_soc_platform_register(&pdev->dev);
 	if (ret) {
 		dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
-		goto err_unregister_dai;
+		goto err_unregister_component;
 	}
 
 	return 0;
 
-err_unregister_dai:
-	snd_soc_unregister_dai(&pdev->dev);
+err_unregister_component:
+	snd_soc_unregister_component(&pdev->dev);
 err_release_clk:
 	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
@@ -1194,7 +1238,7 @@ err_release_clk:
 static int davinci_mcasp_remove(struct platform_device *pdev)
 {
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	davinci_soc_platform_unregister(&pdev->dev);
 
 	pm_runtime_put_sync(&pdev->dev);
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h
index 0edd3b5a37fd..a9ac0c11da71 100644
--- a/sound/soc/davinci/davinci-mcasp.h
+++ b/sound/soc/davinci/davinci-mcasp.h
@@ -38,7 +38,7 @@ struct davinci_audio_dev {
 	u8	num_serializer;
 	u8	*serial_dir;
 	u8	version;
-	u8	bclk_lrclk_ratio;
+	u16	bclk_lrclk_ratio;
 
 	/* McASP FIFO related */
 	u8	txnumevt;
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index afab81f844ae..b2f27c2e5fdc 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -200,7 +200,7 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
 		src = dma_pos;
 		dst = prtd->params->dma_addr;
 		src_bidx = data_type;
-		dst_bidx = 0;
+		dst_bidx = 4;
 		src_cidx = data_type * fifo_level;
 		dst_cidx = 0;
 	} else {
@@ -223,9 +223,10 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
 		edma_set_transfer_params(prtd->asp_link[0], acnt, count, 1, 0,
 							ASYNC);
 	else
-		edma_set_transfer_params(prtd->asp_link[0], acnt, fifo_level,
-							count, fifo_level,
-							ABSYNC);
+		edma_set_transfer_params(prtd->asp_link[0], acnt,
+						fifo_level,
+						count, fifo_level,
+						ABSYNC);
 }
 
 static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data)
diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c
index 07bde2e6f84e..30587c0cdbd2 100644
--- a/sound/soc/davinci/davinci-vcif.c
+++ b/sound/soc/davinci/davinci-vcif.c
@@ -204,6 +204,10 @@ static struct snd_soc_dai_driver davinci_vcif_dai = {
 
 };
 
+static const struct snd_soc_component_driver davinci_vcif_component = {
+	.name		= "davinci-vcif",
+};
+
 static int davinci_vcif_probe(struct platform_device *pdev)
 {
 	struct davinci_vc *davinci_vc = pdev->dev.platform_data;
@@ -234,7 +238,8 @@ static int davinci_vcif_probe(struct platform_device *pdev)
 
 	dev_set_drvdata(&pdev->dev, davinci_vcif_dev);
 
-	ret = snd_soc_register_dai(&pdev->dev, &davinci_vcif_dai);
+	ret = snd_soc_register_component(&pdev->dev, &davinci_vcif_component,
+					 &davinci_vcif_dai, 1);
 	if (ret != 0) {
 		dev_err(&pdev->dev, "could not register dai\n");
 		return ret;
@@ -243,7 +248,7 @@ static int davinci_vcif_probe(struct platform_device *pdev)
 	ret = davinci_soc_platform_register(&pdev->dev);
 	if (ret) {
 		dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
-		snd_soc_unregister_dai(&pdev->dev);
+		snd_soc_unregister_component(&pdev->dev);
 		return ret;
 	}
 
@@ -252,7 +257,7 @@ static int davinci_vcif_probe(struct platform_device *pdev)
 
 static int davinci_vcif_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	davinci_soc_platform_unregister(&pdev->dev);
 
 	return 0;
diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c
index deb30d59965e..593a3ea12d4c 100644
--- a/sound/soc/dwc/designware_i2s.c
+++ b/sound/soc/dwc/designware_i2s.c
@@ -297,6 +297,10 @@ static struct snd_soc_dai_ops dw_i2s_dai_ops = {
 	.trigger	= dw_i2s_trigger,
 };
 
+static const struct snd_soc_component_driver dw_i2s_component = {
+	.name		= "dw-i2s",
+};
+
 #ifdef CONFIG_PM
 
 static int dw_i2s_suspend(struct snd_soc_dai *dai)
@@ -413,7 +417,8 @@ static int dw_i2s_probe(struct platform_device *pdev)
 
 	dev->dev = &pdev->dev;
 	dev_set_drvdata(&pdev->dev, dev);
-	ret = snd_soc_register_dai(&pdev->dev, dw_i2s_dai);
+	ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component,
+					 dw_i2s_dai, 1);
 	if (ret != 0) {
 		dev_err(&pdev->dev, "not able to register dai\n");
 		goto err_set_drvdata;
@@ -434,7 +439,7 @@ static int dw_i2s_remove(struct platform_device *pdev)
 {
 	struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	dev_set_drvdata(&pdev->dev, NULL);
 
 	clk_put(dev->clk);
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 3b98159d9645..3843a18d4e56 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -118,7 +118,7 @@ config SND_SOC_IMX_PCM_FIQ
 
 config SND_SOC_IMX_PCM_DMA
 	bool
-	select SND_SOC_DMAENGINE_PCM
+	select SND_SOC_GENERIC_DMAENGINE_PCM
 	select SND_SOC_IMX_PCM
 
 config SND_SOC_IMX_AUDMUX
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 7decbd9b2340..0f0bed6def9e 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -27,6 +27,7 @@
 #include <sound/pcm_params.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
 #include "fsl_ssi.h"
 #include "imx-pcm.h"
@@ -122,8 +123,10 @@ struct fsl_ssi_private {
 	bool ssi_on_imx;
 	struct clk *clk;
 	struct platform_device *imx_pcm_pdev;
-	struct imx_pcm_dma_params dma_params_tx;
-	struct imx_pcm_dma_params dma_params_rx;
+	struct snd_dmaengine_dai_dma_data dma_params_tx;
+	struct snd_dmaengine_dai_dma_data dma_params_rx;
+	struct imx_dma_data filter_data_tx;
+	struct imx_dma_data filter_data_rx;
 
 	struct {
 		unsigned int rfrc;
@@ -422,12 +425,6 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
 		ssi_private->second_stream = substream;
 	}
 
-	if (ssi_private->ssi_on_imx)
-		snd_soc_dai_set_dma_data(dai, substream,
-			(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-				&ssi_private->dma_params_tx :
-				&ssi_private->dma_params_rx);
-
 	return 0;
 }
 
@@ -549,6 +546,18 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
 	}
 }
 
+static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
+{
+	struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(dai);
+
+	if (ssi_private->ssi_on_imx) {
+		dai->playback_dma_data = &ssi_private->dma_params_tx;
+		dai->capture_dma_data = &ssi_private->dma_params_rx;
+	}
+
+	return 0;
+}
+
 static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
 	.startup	= fsl_ssi_startup,
 	.hw_params	= fsl_ssi_hw_params,
@@ -558,6 +567,7 @@ static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
 
 /* Template for the CPU dai driver structure */
 static struct snd_soc_dai_driver fsl_ssi_dai_template = {
+	.probe = fsl_ssi_dai_probe,
 	.playback = {
 		/* The SSI does not support monaural audio. */
 		.channels_min = 2,
@@ -574,6 +584,10 @@ static struct snd_soc_dai_driver fsl_ssi_dai_template = {
 	.ops = &fsl_ssi_dai_ops,
 };
 
+static const struct snd_soc_component_driver fsl_ssi_component = {
+	.name		= "fsl-ssi",
+};
+
 /* Show the statistics of a flag only if its interrupt is enabled.  The
  * compiler will optimze this code to a no-op if the interrupt is not
  * enabled.
@@ -649,6 +663,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
 	const uint32_t *iprop;
 	struct resource res;
 	char name[64];
+	bool shared;
 
 	/* SSIs that are not connected on the board should have a
 	 *      status = "disabled"
@@ -737,14 +752,18 @@ static int fsl_ssi_probe(struct platform_device *pdev)
 		 * We have burstsize be "fifo_depth - 2" to match the SSI
 		 * watermark setting in fsl_ssi_startup().
 		 */
-		ssi_private->dma_params_tx.burstsize =
+		ssi_private->dma_params_tx.maxburst =
 			ssi_private->fifo_depth - 2;
-		ssi_private->dma_params_rx.burstsize =
+		ssi_private->dma_params_rx.maxburst =
 			ssi_private->fifo_depth - 2;
-		ssi_private->dma_params_tx.dma_addr =
+		ssi_private->dma_params_tx.addr =
 			ssi_private->ssi_phys + offsetof(struct ccsr_ssi, stx0);
-		ssi_private->dma_params_rx.dma_addr =
+		ssi_private->dma_params_rx.addr =
 			ssi_private->ssi_phys + offsetof(struct ccsr_ssi, srx0);
+		ssi_private->dma_params_tx.filter_data =
+			&ssi_private->filter_data_tx;
+		ssi_private->dma_params_rx.filter_data =
+			&ssi_private->filter_data_rx;
 		/*
 		 * TODO: This is a temporary solution and should be changed
 		 * to use generic DMA binding later when the helplers get in.
@@ -755,14 +774,14 @@ static int fsl_ssi_probe(struct platform_device *pdev)
 			dev_err(&pdev->dev, "could not get dma events\n");
 			goto error_clk;
 		}
-		ssi_private->dma_params_tx.dma = dma_events[0];
-		ssi_private->dma_params_rx.dma = dma_events[1];
 
-		ssi_private->dma_params_tx.shared_peripheral =
-				of_device_is_compatible(of_get_parent(np),
-							"fsl,spba-bus");
-		ssi_private->dma_params_rx.shared_peripheral =
-				ssi_private->dma_params_tx.shared_peripheral;
+		shared = of_device_is_compatible(of_get_parent(np),
+			    "fsl,spba-bus");
+
+		imx_pcm_dma_params_init_data(&ssi_private->filter_data_tx,
+			dma_events[0], shared);
+		imx_pcm_dma_params_init_data(&ssi_private->filter_data_rx,
+			dma_events[1], shared);
 	}
 
 	/* Initialize the the device_attribute structure */
@@ -782,7 +801,8 @@ static int fsl_ssi_probe(struct platform_device *pdev)
 	/* Register with ASoC */
 	dev_set_drvdata(&pdev->dev, ssi_private);
 
-	ret = snd_soc_register_dai(&pdev->dev, &ssi_private->cpu_dai_drv);
+	ret = snd_soc_register_component(&pdev->dev, &fsl_ssi_component,
+					 &ssi_private->cpu_dai_drv, 1);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
 		goto error_dev;
@@ -835,7 +855,7 @@ done:
 error_dai:
 	if (ssi_private->ssi_on_imx)
 		platform_device_unregister(ssi_private->imx_pcm_pdev);
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 error_dev:
 	dev_set_drvdata(&pdev->dev, NULL);
@@ -873,7 +893,7 @@ static int fsl_ssi_remove(struct platform_device *pdev)
 		clk_disable_unprepare(ssi_private->clk);
 		clk_put(ssi_private->clk);
 	}
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	device_remove_file(&pdev->dev, &ssi_private->dev_attr);
 
 	free_irq(ssi_private->irq, ssi_private);
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h
index 217300029b5b..e6b9a69e2a68 100644
--- a/sound/soc/fsl/fsl_ssi.h
+++ b/sound/soc/fsl/fsl_ssi.h
@@ -196,5 +196,13 @@ struct ccsr_ssi {
 #define CCSR_SSI_SOR_WAIT(x) (((x) & 3) << CCSR_SSI_SOR_WAIT_SHIFT)
 #define CCSR_SSI_SOR_SYNRST 		0x00000001
 
+#define CCSR_SSI_SACNT_FRDIV(x)		(((x) & 0x3f) << 5)
+#define CCSR_SSI_SACNT_WR		0x00000010
+#define CCSR_SSI_SACNT_RD		0x00000008
+#define CCSR_SSI_SACNT_RDWR_MASK	0x00000018
+#define CCSR_SSI_SACNT_TIF		0x00000004
+#define CCSR_SSI_SACNT_FV		0x00000002
+#define CCSR_SSI_SACNT_AC97EN		0x00000001
+
 #endif
 
diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c
index 3f333e5b4673..47f046a8fdab 100644
--- a/sound/soc/fsl/imx-audmux.c
+++ b/sound/soc/fsl/imx-audmux.c
@@ -262,7 +262,7 @@ static int imx_audmux_probe(struct platform_device *pdev)
 		return PTR_ERR(pinctrl);
 	}
 
-	audmux_clk = clk_get(&pdev->dev, "audmux");
+	audmux_clk = devm_clk_get(&pdev->dev, "audmux");
 	if (IS_ERR(audmux_clk)) {
 		dev_dbg(&pdev->dev, "cannot get clock: %ld\n",
 				PTR_ERR(audmux_clk));
@@ -282,7 +282,6 @@ static int imx_audmux_remove(struct platform_device *pdev)
 {
 	if (audmux_type == IMX31_AUDMUX)
 		audmux_debugfs_remove();
-	clk_put(audmux_clk);
 
 	return 0;
 }
diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c
index 500f8ce55d78..c246fb514930 100644
--- a/sound/soc/fsl/imx-pcm-dma.c
+++ b/sound/soc/fsl/imx-pcm-dma.c
@@ -11,74 +11,30 @@
  *  Free Software Foundation;  either version 2 of the  License, or (at your
  *  option) any later version.
  */
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/slab.h>
 #include <linux/dmaengine.h>
 #include <linux/types.h>
 
 #include <sound/core.h>
-#include <sound/initval.h>
 #include <sound/pcm.h>
-#include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/dmaengine_pcm.h>
 
-#include <linux/platform_data/dma-imx.h>
-
 #include "imx-pcm.h"
 
 static bool filter(struct dma_chan *chan, void *param)
 {
+	struct snd_dmaengine_dai_dma_data *dma_data = param;
+
 	if (!imx_dma_is_general_purpose(chan))
 		return false;
 
-	chan->private = param;
+	chan->private = dma_data->filter_data;
 
 	return true;
 }
 
-static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
-	struct imx_pcm_dma_params *dma_params;
-	struct dma_slave_config slave_config;
-	int ret;
-
-	dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-	ret = snd_hwparams_to_dma_slave_config(substream, params, &slave_config);
-	if (ret)
-		return ret;
-
-	slave_config.device_fc = false;
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		slave_config.dst_addr = dma_params->dma_addr;
-		slave_config.dst_maxburst = dma_params->burstsize;
-	} else {
-		slave_config.src_addr = dma_params->dma_addr;
-		slave_config.src_maxburst = dma_params->burstsize;
-	}
-
-	ret = dmaengine_slave_config(chan, &slave_config);
-	if (ret)
-		return ret;
-
-	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-
-	return 0;
-}
-
-static struct snd_pcm_hardware snd_imx_hardware = {
+static const struct snd_pcm_hardware imx_pcm_hardware = {
 	.info = SNDRV_PCM_INFO_INTERLEAVED |
 		SNDRV_PCM_INFO_BLOCK_TRANSFER |
 		SNDRV_PCM_INFO_MMAP |
@@ -97,64 +53,22 @@ static struct snd_pcm_hardware snd_imx_hardware = {
 	.fifo_size = 0,
 };
 
-static int snd_imx_open(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct imx_pcm_dma_params *dma_params;
-	struct imx_dma_data *dma_data;
-	int ret;
-
-	snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
-
-	dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-	dma_data = kzalloc(sizeof(*dma_data), GFP_KERNEL);
-	if (!dma_data)
-		return -ENOMEM;
-
-	dma_data->peripheral_type = dma_params->shared_peripheral ?
-					IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI;
-	dma_data->priority = DMA_PRIO_HIGH;
-	dma_data->dma_request = dma_params->dma;
-
-	ret = snd_dmaengine_pcm_open(substream, filter, dma_data);
-	if (ret) {
-		kfree(dma_data);
-		return ret;
-	}
-
-	snd_dmaengine_pcm_set_data(substream, dma_data);
-
-	return 0;
-}
+static const struct snd_dmaengine_pcm_config imx_dmaengine_pcm_config = {
+	.pcm_hardware = &imx_pcm_hardware,
+	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+	.compat_filter_fn = filter,
+	.prealloc_buffer_size = IMX_SSI_DMABUF_SIZE,
+};
 
-static int snd_imx_close(struct snd_pcm_substream *substream)
+int imx_pcm_dma_init(struct platform_device *pdev)
 {
-	struct imx_dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
-
-	snd_dmaengine_pcm_close(substream);
-	kfree(dma_data);
-
-	return 0;
+	return snd_dmaengine_pcm_register(&pdev->dev, &imx_dmaengine_pcm_config,
+		SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
+		SND_DMAENGINE_PCM_FLAG_NO_DT |
+		SND_DMAENGINE_PCM_FLAG_COMPAT);
 }
 
-static struct snd_pcm_ops imx_pcm_ops = {
-	.open		= snd_imx_open,
-	.close		= snd_imx_close,
-	.ioctl		= snd_pcm_lib_ioctl,
-	.hw_params	= snd_imx_pcm_hw_params,
-	.trigger	= snd_dmaengine_pcm_trigger,
-	.pointer	= snd_dmaengine_pcm_pointer_no_residue,
-	.mmap		= snd_imx_pcm_mmap,
-};
-
-static struct snd_soc_platform_driver imx_soc_platform_mx2 = {
-	.ops		= &imx_pcm_ops,
-	.pcm_new	= imx_pcm_new,
-	.pcm_free	= imx_pcm_free,
-};
-
-int imx_pcm_dma_init(struct platform_device *pdev)
+void imx_pcm_dma_exit(struct platform_device *pdev)
 {
-	return snd_soc_register_platform(&pdev->dev, &imx_soc_platform_mx2);
+	snd_dmaengine_pcm_unregister(&pdev->dev);
 }
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
index 920f945cb2f4..670b96b0ce2f 100644
--- a/sound/soc/fsl/imx-pcm-fiq.c
+++ b/sound/soc/fsl/imx-pcm-fiq.c
@@ -34,7 +34,7 @@
 #include "imx-ssi.h"
 
 struct imx_pcm_runtime_data {
-	int period;
+	unsigned int period;
 	int periods;
 	unsigned long offset;
 	unsigned long last_offset;
@@ -299,8 +299,8 @@ int imx_pcm_fiq_init(struct platform_device *pdev)
 
 	imx_ssi_fiq_base = (unsigned long)ssi->base;
 
-	ssi->dma_params_tx.burstsize = 4;
-	ssi->dma_params_rx.burstsize = 6;
+	ssi->dma_params_tx.maxburst = 4;
+	ssi->dma_params_rx.maxburst = 6;
 
 	ret = snd_soc_register_platform(&pdev->dev, &imx_soc_platform_fiq);
 	if (ret)
diff --git a/sound/soc/fsl/imx-pcm.c b/sound/soc/fsl/imx-pcm.c
index 0d0625bfcb65..c49896442d8e 100644
--- a/sound/soc/fsl/imx-pcm.c
+++ b/sound/soc/fsl/imx-pcm.c
@@ -114,7 +114,11 @@ static int imx_pcm_probe(struct platform_device *pdev)
 
 static int imx_pcm_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_platform(&pdev->dev);
+	if (strcmp(pdev->id_entry->name, "imx-fiq-pcm-audio") == 0)
+		snd_soc_unregister_platform(&pdev->dev);
+	else
+		imx_pcm_dma_exit(pdev);
+
 	return 0;
 }
 
diff --git a/sound/soc/fsl/imx-pcm.h b/sound/soc/fsl/imx-pcm.h
index 5ae13a13a353..b7fa0d75c687 100644
--- a/sound/soc/fsl/imx-pcm.h
+++ b/sound/soc/fsl/imx-pcm.h
@@ -13,17 +13,24 @@
 #ifndef _IMX_PCM_H
 #define _IMX_PCM_H
 
+#include <linux/platform_data/dma-imx.h>
+
 /*
  * Do not change this as the FIQ handler depends on this size
  */
 #define IMX_SSI_DMABUF_SIZE	(64 * 1024)
 
-struct imx_pcm_dma_params {
-	int dma;
-	unsigned long dma_addr;
-	int burstsize;
-	bool shared_peripheral;	/* The peripheral is on SPBA bus */
-};
+static inline void
+imx_pcm_dma_params_init_data(struct imx_dma_data *dma_data,
+	int dma, bool shared)
+{
+	dma_data->dma_request = dma;
+	dma_data->priority = DMA_PRIO_HIGH;
+	if (shared)
+		dma_data->peripheral_type = IMX_DMATYPE_SSI_SP;
+	else
+		dma_data->peripheral_type = IMX_DMATYPE_SSI;
+}
 
 int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
 		     struct vm_area_struct *vma);
@@ -32,11 +39,16 @@ void imx_pcm_free(struct snd_pcm *pcm);
 
 #ifdef CONFIG_SND_SOC_IMX_PCM_DMA
 int imx_pcm_dma_init(struct platform_device *pdev);
+void imx_pcm_dma_exit(struct platform_device *pdev);
 #else
 static inline int imx_pcm_dma_init(struct platform_device *pdev)
 {
 	return -ENODEV;
 }
+
+static inline void imx_pcm_dma_exit(struct platform_device *pdev)
+{
+}
 #endif
 
 #ifdef CONFIG_SND_SOC_IMX_PCM_FIQ
diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c
index 424347e9b2d7..9584e78858df 100644
--- a/sound/soc/fsl/imx-sgtl5000.c
+++ b/sound/soc/fsl/imx-sgtl5000.c
@@ -148,7 +148,7 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
 	data->dai.stream_name = "HiFi";
 	data->dai.codec_dai_name = "sgtl5000";
 	data->dai.codec_of_node = codec_np;
-	data->dai.cpu_dai_name = dev_name(&ssi_pdev->dev);
+	data->dai.cpu_of_node = ssi_np;
 	data->dai.platform_name = "imx-pcm-audio";
 	data->dai.init = &imx_sgtl5000_dai_init;
 	data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c
index 810c7eeb7b03..902fab02b851 100644
--- a/sound/soc/fsl/imx-ssi.c
+++ b/sound/soc/fsl/imx-ssi.c
@@ -232,23 +232,6 @@ static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
 	return 0;
 }
 
-static int imx_ssi_startup(struct snd_pcm_substream *substream,
-			   struct snd_soc_dai *cpu_dai)
-{
-	struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
-	struct imx_pcm_dma_params *dma_data;
-
-	/* Tx/Rx config */
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		dma_data = &ssi->dma_params_tx;
-	else
-		dma_data = &ssi->dma_params_rx;
-
-	snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
-
-	return 0;
-}
-
 /*
  * Should only be called when port is inactive (i.e. SSIEN = 0),
  * although can be called multiple times by upper layers.
@@ -353,7 +336,6 @@ static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
 }
 
 static const struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
-	.startup	= imx_ssi_startup,
 	.hw_params	= imx_ssi_hw_params,
 	.set_fmt	= imx_ssi_set_dai_fmt,
 	.set_clkdiv	= imx_ssi_set_dai_clkdiv,
@@ -369,10 +351,14 @@ static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
 
 	snd_soc_dai_set_drvdata(dai, ssi);
 
-	val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) |
-		SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize);
+	val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.maxburst) |
+		SSI_SFCSR_RFWM0(ssi->dma_params_rx.maxburst);
 	writel(val, ssi->base + SSI_SFCSR);
 
+	/* Tx/Rx config */
+	dai->playback_dma_data = &ssi->dma_params_tx;
+	dai->capture_dma_data = &ssi->dma_params_rx;
+
 	return 0;
 }
 
@@ -400,7 +386,7 @@ static struct snd_soc_dai_driver imx_ac97_dai = {
 		.stream_name = "AC97 Playback",
 		.channels_min = 2,
 		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_48000,
+		.rates = SNDRV_PCM_RATE_8000_48000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 	},
 	.capture = {
@@ -413,6 +399,10 @@ static struct snd_soc_dai_driver imx_ac97_dai = {
 	.ops = &imx_ssi_pcm_dai_ops,
 };
 
+static const struct snd_soc_component_driver imx_component = {
+	.name		= DRV_NAME,
+};
+
 static void setup_channel_to_ac97(struct imx_ssi *imx_ssi)
 {
 	void __iomem *base = imx_ssi->base;
@@ -575,23 +565,31 @@ static int imx_ssi_probe(struct platform_device *pdev)
 
 	writel(0x0, ssi->base + SSI_SIER);
 
-	ssi->dma_params_rx.dma_addr = res->start + SSI_SRX0;
-	ssi->dma_params_tx.dma_addr = res->start + SSI_STX0;
+	ssi->dma_params_rx.addr = res->start + SSI_SRX0;
+	ssi->dma_params_tx.addr = res->start + SSI_STX0;
+
+	ssi->dma_params_tx.maxburst = 6;
+	ssi->dma_params_rx.maxburst = 4;
 
-	ssi->dma_params_tx.burstsize = 6;
-	ssi->dma_params_rx.burstsize = 4;
+	ssi->dma_params_tx.filter_data = &ssi->filter_data_tx;
+	ssi->dma_params_rx.filter_data = &ssi->filter_data_rx;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
-	if (res)
-		ssi->dma_params_tx.dma = res->start;
+	if (res) {
+		imx_pcm_dma_params_init_data(&ssi->filter_data_tx, res->start,
+			false);
+	}
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0");
-	if (res)
-		ssi->dma_params_rx.dma = res->start;
+	if (res) {
+		imx_pcm_dma_params_init_data(&ssi->filter_data_rx, res->start,
+			false);
+	}
 
 	platform_set_drvdata(pdev, ssi);
 
-	ret = snd_soc_register_dai(&pdev->dev, dai);
+	ret = snd_soc_register_component(&pdev->dev, &imx_component,
+					 dai, 1);
 	if (ret) {
 		dev_err(&pdev->dev, "register DAI failed\n");
 		goto failed_register;
@@ -632,7 +630,7 @@ failed_pdev_alloc:
 failed_pdev_fiq_add:
 	platform_device_put(ssi->soc_platform_pdev_fiq);
 failed_pdev_fiq_alloc:
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 failed_register:
 	release_mem_region(res->start, resource_size(res));
 failed_get_resource:
@@ -650,7 +648,7 @@ static int imx_ssi_remove(struct platform_device *pdev)
 	platform_device_unregister(ssi->soc_platform_pdev);
 	platform_device_unregister(ssi->soc_platform_pdev_fiq);
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	if (ssi->flags & IMX_SSI_USE_AC97)
 		ac97_ssi = NULL;
diff --git a/sound/soc/fsl/imx-ssi.h b/sound/soc/fsl/imx-ssi.h
index dc114bdedce5..bb6b3dbb13fd 100644
--- a/sound/soc/fsl/imx-ssi.h
+++ b/sound/soc/fsl/imx-ssi.h
@@ -187,6 +187,7 @@
 
 #include <linux/dmaengine.h>
 #include <linux/platform_data/dma-imx.h>
+#include <sound/dmaengine_pcm.h>
 #include "imx-pcm.h"
 
 struct imx_ssi {
@@ -204,8 +205,10 @@ struct imx_ssi {
 	void (*ac97_reset) (struct snd_ac97 *ac97);
 	void (*ac97_warm_reset)(struct snd_ac97 *ac97);
 
-	struct imx_pcm_dma_params	dma_params_rx;
-	struct imx_pcm_dma_params	dma_params_tx;
+	struct snd_dmaengine_dai_dma_data dma_params_rx;
+	struct snd_dmaengine_dai_dma_data dma_params_tx;
+	struct imx_dma_data filter_data_tx;
+	struct imx_dma_data filter_data_rx;
 
 	int enabled;
 
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
index a4aec0488dd3..4141b35ef0bb 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.c
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -270,6 +270,9 @@ static struct snd_soc_dai_driver psc_ac97_dai[] = {
 	.ops = &psc_ac97_digital_ops,
 } };
 
+static const struct snd_soc_component_driver psc_ac97_component = {
+	.name		= DRV_NAME,
+};
 
 
 /* ---------------------------------------------------------------------
@@ -287,7 +290,8 @@ static int psc_ac97_of_probe(struct platform_device *op)
 	if (rc != 0)
 		return rc;
 
-	rc = snd_soc_register_dais(&op->dev, psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
+	rc = snd_soc_register_component(&op->dev, &psc_ac97_component,
+					psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
 	if (rc != 0) {
 		dev_err(&op->dev, "Failed to register DAI\n");
 		return rc;
@@ -313,7 +317,7 @@ static int psc_ac97_of_probe(struct platform_device *op)
 static int psc_ac97_of_remove(struct platform_device *op)
 {
 	mpc5200_audio_dma_destroy(op);
-	snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_ac97_dai));
+	snd_soc_unregister_component(&op->dev);
 	return 0;
 }
 
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
index b95b966f25a0..f4efaadb80a2 100644
--- a/sound/soc/fsl/mpc5200_psc_i2s.c
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -148,6 +148,10 @@ static struct snd_soc_dai_driver psc_i2s_dai[] = {{
 	.ops = &psc_i2s_dai_ops,
 } };
 
+static const struct snd_soc_component_driver psc_i2s_component = {
+	.name		= "mpc5200-i2s",
+};
+
 /* ---------------------------------------------------------------------
  * OF platform bus binding code:
  * - Probe/remove operations
@@ -163,7 +167,8 @@ static int psc_i2s_of_probe(struct platform_device *op)
 	if (rc != 0)
 		return rc;
 
-	rc = snd_soc_register_dais(&op->dev, psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
+	rc = snd_soc_register_component(&op->dev, &psc_i2s_component,
+					psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
 	if (rc != 0) {
 		pr_err("Failed to register DAI\n");
 		return rc;
@@ -208,7 +213,7 @@ static int psc_i2s_of_probe(struct platform_device *op)
 static int psc_i2s_of_remove(struct platform_device *op)
 {
 	mpc5200_audio_dma_destroy(op);
-	snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_i2s_dai));
+	snd_soc_unregister_component(&op->dev);
 	return 0;
 }
 
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
index 6cef491f4823..9a126441c5f3 100644
--- a/sound/soc/jz4740/jz4740-i2s.c
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -425,6 +425,10 @@ static struct snd_soc_dai_driver jz4740_i2s_dai = {
 	.resume = jz4740_i2s_resume,
 };
 
+static const struct snd_soc_component_driver jz4740_i2s_component = {
+	.name		= "jz4740-i2s",
+};
+
 static int jz4740_i2s_dev_probe(struct platform_device *pdev)
 {
 	struct jz4740_i2s *i2s;
@@ -469,7 +473,8 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev)
 	}
 
 	platform_set_drvdata(pdev, i2s);
-	ret = snd_soc_register_dai(&pdev->dev, &jz4740_i2s_dai);
+	ret = snd_soc_register_component(&pdev->dev, &jz4740_i2s_component,
+					 &jz4740_i2s_dai, 1);
 
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register DAI\n");
@@ -496,7 +501,7 @@ static int jz4740_i2s_dev_remove(struct platform_device *pdev)
 {
 	struct jz4740_i2s *i2s = platform_get_drvdata(pdev);
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	clk_put(i2s->clk_i2s);
 	clk_put(i2s->clk_aic);
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
index c74c89065493..befe68f59285 100644
--- a/sound/soc/kirkwood/kirkwood-i2s.c
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -451,6 +451,10 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = {
 	.ops = &kirkwood_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver kirkwood_i2s_component = {
+	.name		= DRV_NAME,
+};
+
 static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
 {
 	struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data;
@@ -524,10 +528,11 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
 		priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128;
 	}
 
-	err = snd_soc_register_dai(&pdev->dev, soc_dai);
+	err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component,
+					 soc_dai, 1);
 	if (!err)
 		return 0;
-	dev_err(&pdev->dev, "snd_soc_register_dai failed\n");
+	dev_err(&pdev->dev, "snd_soc_register_component failed\n");
 
 	if (!IS_ERR(priv->extclk)) {
 		clk_disable_unprepare(priv->extclk);
@@ -542,7 +547,7 @@ static int kirkwood_i2s_dev_remove(struct platform_device *pdev)
 {
 	struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev);
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	if (!IS_ERR(priv->extclk)) {
 		clk_disable_unprepare(priv->extclk);
diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c
index a263cbed8624..392fc0b8f5b8 100644
--- a/sound/soc/mid-x86/sst_platform.c
+++ b/sound/soc/mid-x86/sst_platform.c
@@ -1,7 +1,7 @@
 /*
  *  sst_platform.c - Intel MID Platform driver
  *
- *  Copyright (C) 2010-2012 Intel Corp
+ *  Copyright (C) 2010-2013 Intel Corp
  *  Author: Vinod Koul <vinod.koul@intel.com>
  *  Author: Harsha Priya <priya.harsha@intel.com>
  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -165,6 +165,10 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
 },
 };
 
+static const struct snd_soc_component_driver sst_component = {
+	.name		= "sst",
+};
+
 /* helper functions */
 static inline void sst_set_stream_status(struct sst_runtime_stream *stream,
 					int state)
@@ -652,11 +656,21 @@ static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
 	return stream->compr_ops->get_codec_caps(codec);
 }
 
+static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
+					struct snd_compr_metadata *metadata)
+{
+	struct sst_runtime_stream *stream  =
+		 cstream->runtime->private_data;
+
+	return stream->compr_ops->set_metadata(stream->id, metadata);
+}
+
 static struct snd_compr_ops sst_platform_compr_ops = {
 
 	.open = sst_platform_compr_open,
 	.free = sst_platform_compr_free,
 	.set_params = sst_platform_compr_set_params,
+	.set_metadata = sst_platform_compr_set_metadata,
 	.trigger = sst_platform_compr_trigger,
 	.pointer = sst_platform_compr_pointer,
 	.ack = sst_platform_compr_ack,
@@ -683,7 +697,7 @@ static int sst_platform_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	ret = snd_soc_register_dais(&pdev->dev,
+	ret = snd_soc_register_component(&pdev->dev, &sst_component,
 				sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
 	if (ret) {
 		pr_err("registering cpu dais failed\n");
@@ -695,7 +709,7 @@ static int sst_platform_probe(struct platform_device *pdev)
 static int sst_platform_remove(struct platform_device *pdev)
 {
 
-	snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sst_platform_dai));
+	snd_soc_unregister_component(&pdev->dev);
 	snd_soc_unregister_platform(&pdev->dev);
 	pr_debug("sst_platform_remove success\n");
 	return 0;
diff --git a/sound/soc/mid-x86/sst_platform.h b/sound/soc/mid-x86/sst_platform.h
index d61c5d514ffa..cacc9066ec52 100644
--- a/sound/soc/mid-x86/sst_platform.h
+++ b/sound/soc/mid-x86/sst_platform.h
@@ -124,6 +124,8 @@ struct compress_sst_ops {
 	int (*close) (unsigned int str_id);
 	int (*get_caps) (struct snd_compr_caps *caps);
 	int (*get_codec_caps) (struct snd_compr_codec_caps *codec);
+	int (*set_metadata) (unsigned int str_id,
+			struct snd_compr_metadata *mdata);
 
 };
 
diff --git a/sound/soc/mxs/Kconfig b/sound/soc/mxs/Kconfig
index b6fa77678d97..78d321cbe8b4 100644
--- a/sound/soc/mxs/Kconfig
+++ b/sound/soc/mxs/Kconfig
@@ -1,7 +1,7 @@
 menuconfig SND_MXS_SOC
 	tristate "SoC Audio for Freescale MXS CPUs"
 	depends on ARCH_MXS
-	select SND_SOC_DMAENGINE_PCM
+	select SND_SOC_GENERIC_DMAENGINE_PCM
 	help
 	  Say Y or M if you want to add support for codecs attached to
 	  the MXS SAIF interface.
diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c
index 564b5b60319d..b41fffc056fb 100644
--- a/sound/soc/mxs/mxs-pcm.c
+++ b/sound/soc/mxs/mxs-pcm.c
@@ -18,38 +18,24 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include <linux/clk.h>
-#include <linux/delay.h>
 #include <linux/device.h>
-#include <linux/dma-mapping.h>
 #include <linux/init.h>
-#include <linux/interrupt.h>
 #include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/dmaengine.h>
-#include <linux/fsl/mxs-dma.h>
 
 #include <sound/core.h>
-#include <sound/initval.h>
 #include <sound/pcm.h>
-#include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/dmaengine_pcm.h>
 
 #include "mxs-pcm.h"
 
-struct mxs_pcm_dma_data {
-	struct mxs_dma_data dma_data;
-	struct mxs_pcm_dma_params *dma_params;
-};
-
-static struct snd_pcm_hardware snd_mxs_hardware = {
+static const struct snd_pcm_hardware snd_mxs_hardware = {
 	.info			= SNDRV_PCM_INFO_MMAP |
 				  SNDRV_PCM_INFO_MMAP_VALID |
 				  SNDRV_PCM_INFO_PAUSE |
 				  SNDRV_PCM_INFO_RESUME |
-				  SNDRV_PCM_INFO_INTERLEAVED,
+				  SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_HALF_DUPLEX,
 	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
 				  SNDRV_PCM_FMTBIT_S20_3LE |
 				  SNDRV_PCM_FMTBIT_S24_LE,
@@ -61,13 +47,11 @@ static struct snd_pcm_hardware snd_mxs_hardware = {
 	.periods_max		= 52,
 	.buffer_bytes_max	= 64 * 1024,
 	.fifo_size		= 32,
-
 };
 
 static bool filter(struct dma_chan *chan, void *param)
 {
-	struct mxs_pcm_dma_data *pcm_dma_data = param;
-	struct mxs_pcm_dma_params *dma_params = pcm_dma_data->dma_params;
+	struct mxs_pcm_dma_params *dma_params = param;
 
 	if (!mxs_dma_is_apbx(chan))
 		return false;
@@ -75,160 +59,30 @@ static bool filter(struct dma_chan *chan, void *param)
 	if (chan->chan_id != dma_params->chan_num)
 		return false;
 
-	chan->private = &pcm_dma_data->dma_data;
+	chan->private = &dma_params->dma_data;
 
 	return true;
 }
 
-static int snd_mxs_pcm_hw_params(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params)
-{
-	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-
-	return 0;
-}
-
-static int snd_mxs_open(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mxs_pcm_dma_data *pcm_dma_data;
-	int ret;
-
-	pcm_dma_data = kzalloc(sizeof(*pcm_dma_data), GFP_KERNEL);
-	if (pcm_dma_data == NULL)
-		return -ENOMEM;
-
-	pcm_dma_data->dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-	pcm_dma_data->dma_data.chan_irq = pcm_dma_data->dma_params->chan_irq;
-
-	ret = snd_dmaengine_pcm_open(substream, filter, pcm_dma_data);
-	if (ret) {
-		kfree(pcm_dma_data);
-		return ret;
-	}
-
-	snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware);
-
-	snd_dmaengine_pcm_set_data(substream, pcm_dma_data);
-
-	return 0;
-}
-
-static int snd_mxs_close(struct snd_pcm_substream *substream)
-{
-	struct mxs_pcm_dma_data *pcm_dma_data = snd_dmaengine_pcm_get_data(substream);
-
-	snd_dmaengine_pcm_close(substream);
-	kfree(pcm_dma_data);
-
-	return 0;
-}
-
-static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream,
-		struct vm_area_struct *vma)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-
-	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
-					runtime->dma_area,
-					runtime->dma_addr,
-					runtime->dma_bytes);
-}
-
-static struct snd_pcm_ops mxs_pcm_ops = {
-	.open		= snd_mxs_open,
-	.close		= snd_mxs_close,
-	.ioctl		= snd_pcm_lib_ioctl,
-	.hw_params	= snd_mxs_pcm_hw_params,
-	.trigger	= snd_dmaengine_pcm_trigger,
-	.pointer	= snd_dmaengine_pcm_pointer_no_residue,
-	.mmap		= snd_mxs_pcm_mmap,
-};
-
-static int mxs_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
-	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-	struct snd_dma_buffer *buf = &substream->dma_buffer;
-	size_t size = snd_mxs_hardware.buffer_bytes_max;
-
-	buf->dev.type = SNDRV_DMA_TYPE_DEV;
-	buf->dev.dev = pcm->card->dev;
-	buf->private_data = NULL;
-	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
-					   &buf->addr, GFP_KERNEL);
-	if (!buf->area)
-		return -ENOMEM;
-	buf->bytes = size;
-
-	return 0;
-}
-
-static u64 mxs_pcm_dmamask = DMA_BIT_MASK(32);
-static int mxs_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_card *card = rtd->card->snd_card;
-	struct snd_pcm *pcm = rtd->pcm;
-	int ret = 0;
-
-	if (!card->dev->dma_mask)
-		card->dev->dma_mask = &mxs_pcm_dmamask;
-	if (!card->dev->coherent_dma_mask)
-		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
-
-	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-		ret = mxs_pcm_preallocate_dma_buffer(pcm,
-			SNDRV_PCM_STREAM_PLAYBACK);
-		if (ret)
-			goto out;
-	}
-
-	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-		ret = mxs_pcm_preallocate_dma_buffer(pcm,
-			SNDRV_PCM_STREAM_CAPTURE);
-		if (ret)
-			goto out;
-	}
-
-out:
-	return ret;
-}
-
-static void mxs_pcm_free(struct snd_pcm *pcm)
-{
-	struct snd_pcm_substream *substream;
-	struct snd_dma_buffer *buf;
-	int stream;
-
-	for (stream = 0; stream < 2; stream++) {
-		substream = pcm->streams[stream].substream;
-		if (!substream)
-			continue;
-
-		buf = &substream->dma_buffer;
-		if (!buf->area)
-			continue;
-
-		dma_free_writecombine(pcm->card->dev, buf->bytes,
-				      buf->area, buf->addr);
-		buf->area = NULL;
-	}
-}
-
-static struct snd_soc_platform_driver mxs_soc_platform = {
-	.ops		= &mxs_pcm_ops,
-	.pcm_new	= mxs_pcm_new,
-	.pcm_free	= mxs_pcm_free,
+static const struct snd_dmaengine_pcm_config mxs_dmaengine_pcm_config = {
+	.pcm_hardware = &snd_mxs_hardware,
+	.compat_filter_fn = filter,
+	.prealloc_buffer_size = 64 * 1024,
 };
 
 int mxs_pcm_platform_register(struct device *dev)
 {
-	return snd_soc_register_platform(dev, &mxs_soc_platform);
+	return snd_dmaengine_pcm_register(dev, &mxs_dmaengine_pcm_config,
+		SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
+		SND_DMAENGINE_PCM_FLAG_NO_DT |
+		SND_DMAENGINE_PCM_FLAG_COMPAT |
+		SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX);
 }
 EXPORT_SYMBOL_GPL(mxs_pcm_platform_register);
 
 void mxs_pcm_platform_unregister(struct device *dev)
 {
-	snd_soc_unregister_platform(dev);
+	snd_dmaengine_pcm_unregister(dev);
 }
 EXPORT_SYMBOL_GPL(mxs_pcm_platform_unregister);
 
diff --git a/sound/soc/mxs/mxs-pcm.h b/sound/soc/mxs/mxs-pcm.h
index 35ba2ca42384..3aa918f9ed3e 100644
--- a/sound/soc/mxs/mxs-pcm.h
+++ b/sound/soc/mxs/mxs-pcm.h
@@ -19,8 +19,10 @@
 #ifndef _MXS_PCM_H
 #define _MXS_PCM_H
 
+#include <linux/fsl/mxs-dma.h>
+
 struct mxs_pcm_dma_params {
-	int chan_irq;
+	struct mxs_dma_data dma_data;
 	int chan_num;
 };
 
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
index 41a6136e3535..d31dc52fa862 100644
--- a/sound/soc/mxs/mxs-saif.c
+++ b/sound/soc/mxs/mxs-saif.c
@@ -370,7 +370,6 @@ static int mxs_saif_startup(struct snd_pcm_substream *substream,
 			   struct snd_soc_dai *cpu_dai)
 {
 	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
-	snd_soc_dai_set_dma_data(cpu_dai, substream, &saif->dma_param);
 
 	/* clear error status to 0 for each re-open */
 	saif->fifo_underrun = 0;
@@ -606,6 +605,8 @@ static int mxs_saif_dai_probe(struct snd_soc_dai *dai)
 	struct mxs_saif *saif = dev_get_drvdata(dai->dev);
 
 	snd_soc_dai_set_drvdata(dai, saif);
+	dai->playback_dma_data = &saif->dma_param;
+	dai->capture_dma_data = &saif->dma_param;
 
 	return 0;
 }
@@ -628,6 +629,10 @@ static struct snd_soc_dai_driver mxs_saif_dai = {
 	.ops = &mxs_saif_dai_ops,
 };
 
+static const struct snd_soc_component_driver mxs_saif_component = {
+	.name		= "mxs-saif",
+};
+
 static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
 {
 	struct mxs_saif *saif = dev_id;
@@ -754,9 +759,9 @@ static int mxs_saif_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	saif->dma_param.chan_irq = platform_get_irq(pdev, 1);
-	if (saif->dma_param.chan_irq < 0) {
-		ret = saif->dma_param.chan_irq;
+	saif->dma_param.dma_data.chan_irq = platform_get_irq(pdev, 1);
+	if (saif->dma_param.dma_data.chan_irq < 0) {
+		ret = saif->dma_param.dma_data.chan_irq;
 		dev_err(&pdev->dev, "failed to get dma irq resource: %d\n",
 			ret);
 		return ret;
@@ -764,7 +769,8 @@ static int mxs_saif_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, saif);
 
-	ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai);
+	ret = snd_soc_register_component(&pdev->dev, &mxs_saif_component,
+					 &mxs_saif_dai, 1);
 	if (ret) {
 		dev_err(&pdev->dev, "register DAI failed\n");
 		return ret;
@@ -779,7 +785,7 @@ static int mxs_saif_probe(struct platform_device *pdev)
 	return 0;
 
 failed_pdev_alloc:
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	return ret;
 }
@@ -787,7 +793,7 @@ failed_pdev_alloc:
 static int mxs_saif_remove(struct platform_device *pdev)
 {
 	mxs_pcm_platform_unregister(&pdev->dev);
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	return 0;
 }
diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c
index 0418467a4848..fe3285ceaf5b 100644
--- a/sound/soc/nuc900/nuc900-ac97.c
+++ b/sound/soc/nuc900/nuc900-ac97.c
@@ -314,6 +314,10 @@ static struct snd_soc_dai_driver nuc900_ac97_dai = {
 	.ops = &nuc900_ac97_dai_ops,
 };
 
+static const struct snd_soc_component_driver nuc900_ac97_component = {
+	.name		= "nuc900-ac97",
+};
+
 static int nuc900_ac97_drvprobe(struct platform_device *pdev)
 {
 	struct nuc900_audio *nuc900_audio;
@@ -361,7 +365,8 @@ static int nuc900_ac97_drvprobe(struct platform_device *pdev)
 
 	nuc900_ac97_data = nuc900_audio;
 
-	ret = snd_soc_register_dai(&pdev->dev, &nuc900_ac97_dai);
+	ret = snd_soc_register_component(&pdev->dev, &nuc900_ac97_component,
+					 &nuc900_ac97_dai, 1);
 	if (ret)
 		goto out3;
 
@@ -384,7 +389,7 @@ out0:
 
 static int nuc900_ac97_drvremove(struct platform_device *pdev)
 {
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	clk_put(nuc900_ac97_data->clk);
 	iounmap(nuc900_ac97_data->mmio);
diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c
index c1900b2a6f28..994dcf345975 100644
--- a/sound/soc/omap/am3517evm.c
+++ b/sound/soc/omap/am3517evm.c
@@ -28,7 +28,6 @@
 #include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include "omap-mcbsp.h"
-#include "omap-pcm.h"
 
 #include "../codecs/tlv320aic23.h"
 
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index 2600447fa74f..629446482a91 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -36,7 +36,6 @@
 #include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include "omap-mcbsp.h"
-#include "omap-pcm.h"
 #include "../codecs/cx20442.h"
 
 
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c
index 285c8368cb47..eb68c7db1cf3 100644
--- a/sound/soc/omap/mcbsp.c
+++ b/sound/soc/omap/mcbsp.c
@@ -1018,9 +1018,10 @@ int omap_mcbsp_init(struct platform_device *pdev)
 		return -ENODEV;
 	}
 	/* RX DMA request number, and port address configuration */
-	mcbsp->dma_data[1].name = "Audio Capture";
-	mcbsp->dma_data[1].dma_req = res->start;
-	mcbsp->dma_data[1].port_addr = omap_mcbsp_dma_reg_params(mcbsp, 1);
+	mcbsp->dma_req[1] = res->start;
+	mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1];
+	mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp, 1);
+	mcbsp->dma_data[1].maxburst = 4;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
 	if (!res) {
@@ -1028,9 +1029,10 @@ int omap_mcbsp_init(struct platform_device *pdev)
 		return -ENODEV;
 	}
 	/* TX DMA request number, and port address configuration */
-	mcbsp->dma_data[0].name = "Audio Playback";
-	mcbsp->dma_data[0].dma_req = res->start;
-	mcbsp->dma_data[0].port_addr = omap_mcbsp_dma_reg_params(mcbsp, 0);
+	mcbsp->dma_req[0] = res->start;
+	mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0];
+	mcbsp->dma_data[0].addr = omap_mcbsp_dma_reg_params(mcbsp, 0);
+	mcbsp->dma_data[0].maxburst = 4;
 
 	mcbsp->fclk = clk_get(&pdev->dev, "fck");
 	if (IS_ERR(mcbsp->fclk)) {
diff --git a/sound/soc/omap/mcbsp.h b/sound/soc/omap/mcbsp.h
index f93e0b0af303..96d1b086bcf8 100644
--- a/sound/soc/omap/mcbsp.h
+++ b/sound/soc/omap/mcbsp.h
@@ -24,14 +24,14 @@
 #ifndef __ASOC_MCBSP_H
 #define __ASOC_MCBSP_H
 
-#include "omap-pcm.h"
-
 #ifdef CONFIG_ARCH_OMAP1
 #define mcbsp_omap1()	1
 #else
 #define mcbsp_omap1()	0
 #endif
 
+#include <sound/dmaengine_pcm.h>
+
 /* McBSP register numbers. Register address offset = num * reg_step */
 enum {
 	/* Common registers */
@@ -312,7 +312,8 @@ struct omap_mcbsp {
 	struct omap_mcbsp_platform_data *pdata;
 	struct omap_mcbsp_st_data *st_data;
 	struct omap_mcbsp_reg_cfg cfg_regs;
-	struct omap_pcm_dma_data dma_data[2];
+	struct snd_dmaengine_dai_dma_data dma_data[2];
+	unsigned int dma_req[2];
 	int dma_op_mode;
 	u16 max_tx_thres;
 	u16 max_rx_thres;
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index ee7cd53aa3ee..5e8d640d314f 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -34,7 +34,6 @@
 #include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include "omap-mcbsp.h"
-#include "omap-pcm.h"
 
 #define N810_HEADSET_AMP_GPIO	10
 #define N810_SPEAKER_AMP_GPIO	101
diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c
index e7d93fa412a9..70cd5c7b2e14 100644
--- a/sound/soc/omap/omap-abe-twl6040.c
+++ b/sound/soc/omap/omap-abe-twl6040.c
@@ -34,7 +34,6 @@
 
 #include "omap-dmic.h"
 #include "omap-mcpdm.h"
-#include "omap-pcm.h"
 #include "../codecs/twl6040.h"
 
 struct abe_twl6040 {
diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c
index ba49ccd9eed9..2ad0370146fd 100644
--- a/sound/soc/omap/omap-dmic.c
+++ b/sound/soc/omap/omap-dmic.c
@@ -39,8 +39,8 @@
 #include <sound/pcm_params.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
-#include "omap-pcm.h"
 #include "omap-dmic.h"
 
 struct omap_dmic {
@@ -55,13 +55,9 @@ struct omap_dmic {
 	u32 ch_enabled;
 	bool active;
 	struct mutex mutex;
-};
 
-/*
- * Stream DMA parameters
- */
-static struct omap_pcm_dma_data omap_dmic_dai_dma_params = {
-	.name		= "DMIC capture",
+	struct snd_dmaengine_dai_dma_data dma_data;
+	unsigned int dma_req;
 };
 
 static inline void omap_dmic_write(struct omap_dmic *dmic, u16 reg, u32 val)
@@ -118,7 +114,7 @@ static int omap_dmic_dai_startup(struct snd_pcm_substream *substream,
 
 	mutex_unlock(&dmic->mutex);
 
-	snd_soc_dai_set_dma_data(dai, substream, &omap_dmic_dai_dma_params);
+	snd_soc_dai_set_dma_data(dai, substream, &dmic->dma_data);
 	return ret;
 }
 
@@ -203,7 +199,7 @@ static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
 				    struct snd_soc_dai *dai)
 {
 	struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
-	struct omap_pcm_dma_data *dma_data;
+	struct snd_dmaengine_dai_dma_data *dma_data;
 	int channels;
 
 	dmic->clk_div = omap_dmic_select_divider(dmic, params_rate(params));
@@ -230,7 +226,7 @@ static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
 
 	/* packet size is threshold * channels */
 	dma_data = snd_soc_dai_get_dma_data(dai, substream);
-	dma_data->packet_size = dmic->threshold * channels;
+	dma_data->maxburst = dmic->threshold * channels;
 
 	return 0;
 }
@@ -448,6 +444,10 @@ static struct snd_soc_dai_driver omap_dmic_dai = {
 	.ops = &omap_dmic_dai_ops,
 };
 
+static const struct snd_soc_component_driver omap_dmic_component = {
+	.name		= "omap-dmic",
+};
+
 static int asoc_dmic_probe(struct platform_device *pdev)
 {
 	struct omap_dmic *dmic;
@@ -476,7 +476,7 @@ static int asoc_dmic_probe(struct platform_device *pdev)
 		ret = -ENODEV;
 		goto err_put_clk;
 	}
-	omap_dmic_dai_dma_params.port_addr = res->start + OMAP_DMIC_DATA_REG;
+	dmic->dma_data.addr = res->start + OMAP_DMIC_DATA_REG;
 
 	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
 	if (!res) {
@@ -484,7 +484,9 @@ static int asoc_dmic_probe(struct platform_device *pdev)
 		ret = -ENODEV;
 		goto err_put_clk;
 	}
-	omap_dmic_dai_dma_params.dma_req = res->start;
+
+	dmic->dma_req = res->start;
+	dmic->dma_data.filter_data = &dmic->dma_req;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
 	if (!res) {
@@ -493,21 +495,12 @@ static int asoc_dmic_probe(struct platform_device *pdev)
 		goto err_put_clk;
 	}
 
-	if (!devm_request_mem_region(&pdev->dev, res->start,
-				     resource_size(res), pdev->name)) {
-		dev_err(dmic->dev, "memory region already claimed\n");
-		ret = -ENODEV;
-		goto err_put_clk;
-	}
-
-	dmic->io_base = devm_ioremap(&pdev->dev, res->start,
-				     resource_size(res));
-	if (!dmic->io_base) {
-		ret = -ENOMEM;
-		goto err_put_clk;
-	}
+	dmic->io_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(dmic->io_base))
+		return PTR_ERR(dmic->io_base);
 
-	ret = snd_soc_register_dai(&pdev->dev, &omap_dmic_dai);
+	ret = snd_soc_register_component(&pdev->dev, &omap_dmic_component,
+					 &omap_dmic_dai, 1);
 	if (ret)
 		goto err_put_clk;
 
@@ -522,7 +515,7 @@ static int asoc_dmic_remove(struct platform_device *pdev)
 {
 	struct omap_dmic *dmic = platform_get_drvdata(pdev);
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	clk_put(dmic->fclk);
 
 	return 0;
diff --git a/sound/soc/omap/omap-hdmi.c b/sound/soc/omap/omap-hdmi.c
index 32fa840c493e..ced3b88b44d4 100644
--- a/sound/soc/omap/omap-hdmi.c
+++ b/sound/soc/omap/omap-hdmi.c
@@ -32,15 +32,16 @@
 #include <sound/soc.h>
 #include <sound/asound.h>
 #include <sound/asoundef.h>
+#include <sound/dmaengine_pcm.h>
 #include <video/omapdss.h>
 
-#include "omap-pcm.h"
 #include "omap-hdmi.h"
 
 #define DRV_NAME "omap-hdmi-audio-dai"
 
 struct hdmi_priv {
-	struct omap_pcm_dma_data dma_params;
+	struct snd_dmaengine_dai_dma_data dma_data;
+	unsigned int dma_req;
 	struct omap_dss_audio dss_audio;
 	struct snd_aes_iec958 iec;
 	struct snd_cea_861_aud_if cea;
@@ -68,7 +69,7 @@ static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream,
 		return -ENODEV;
 	}
 
-	snd_soc_dai_set_dma_data(dai, substream, &priv->dma_params);
+	snd_soc_dai_set_dma_data(dai, substream, &priv->dma_data);
 
 	return 0;
 }
@@ -88,25 +89,20 @@ static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
 	struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
 	struct snd_aes_iec958 *iec = &priv->iec;
 	struct snd_cea_861_aud_if *cea = &priv->cea;
-	struct omap_pcm_dma_data *dma_data;
 	int err = 0;
 
-	dma_data = snd_soc_dai_get_dma_data(dai, substream);
-
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S16_LE:
-		dma_data->packet_size = 16;
+		priv->dma_data.maxburst = 16;
 		break;
 	case SNDRV_PCM_FORMAT_S24_LE:
-		dma_data->packet_size = 32;
+		priv->dma_data.maxburst = 32;
 		break;
 	default:
 		dev_err(dai->dev, "format not supported!\n");
 		return -EINVAL;
 	}
 
-	dma_data->data_type = 32;
-
 	/*
 	 * fill the IEC-60958 channel status word
 	 */
@@ -264,6 +260,10 @@ static struct snd_soc_dai_driver omap_hdmi_dai = {
 	.ops = &omap_hdmi_dai_ops,
 };
 
+static const struct snd_soc_component_driver omap_hdmi_component = {
+	.name		= DRV_NAME,
+};
+
 static int omap_hdmi_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -283,8 +283,7 @@ static int omap_hdmi_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
-	hdmi_data->dma_params.port_addr =  hdmi_rsrc->start
-		+ OMAP_HDMI_AUDIO_DMA_PORT;
+	hdmi_data->dma_data.addr = hdmi_rsrc->start + OMAP_HDMI_AUDIO_DMA_PORT;
 
 	hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_DMA, 0);
 	if (!hdmi_rsrc) {
@@ -292,8 +291,9 @@ static int omap_hdmi_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
-	hdmi_data->dma_params.dma_req =  hdmi_rsrc->start;
-	hdmi_data->dma_params.name = "HDMI playback";
+	hdmi_data->dma_req = hdmi_rsrc->start;
+	hdmi_data->dma_data.filter_data = &hdmi_data->dma_req;
+	hdmi_data->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 
 	/*
 	 * TODO: We assume that there is only one DSS HDMI device. Future
@@ -321,7 +321,8 @@ static int omap_hdmi_probe(struct platform_device *pdev)
 	}
 
 	dev_set_drvdata(&pdev->dev, hdmi_data);
-	ret = snd_soc_register_dai(&pdev->dev, &omap_hdmi_dai);
+	ret = snd_soc_register_component(&pdev->dev, &omap_hdmi_component,
+					 &omap_hdmi_dai, 1);
 
 	return ret;
 }
@@ -330,7 +331,7 @@ static int omap_hdmi_remove(struct platform_device *pdev)
 {
 	struct hdmi_priv *hdmi_data = dev_get_drvdata(&pdev->dev);
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	if (hdmi_data == NULL) {
 		dev_err(&pdev->dev, "cannot obtain HDMi data\n");
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 8d2defd6fdbe..eadbfb6b5000 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -33,11 +33,11 @@
 #include <sound/pcm_params.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
 #include <linux/platform_data/asoc-ti-mcbsp.h>
 #include "mcbsp.h"
 #include "omap-mcbsp.h"
-#include "omap-pcm.h"
 
 #define OMAP_MCBSP_RATES	(SNDRV_PCM_RATE_8000_96000)
 
@@ -62,24 +62,22 @@ enum {
  * Stream DMA parameters. DMA request line and port address are set runtime
  * since they are different between OMAP1 and later OMAPs
  */
-static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
+static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream,
+		unsigned int packet_size)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
-	struct omap_pcm_dma_data *dma_data;
 	int words;
 
-	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
 	/*
 	 * Configure McBSP threshold based on either:
 	 * packet_size, when the sDMA is in packet mode, or based on the
 	 * period size in THRESHOLD mode, otherwise use McBSP threshold = 1
 	 * for mono streams.
 	 */
-	if (dma_data->packet_size)
-		words = dma_data->packet_size;
+	if (packet_size)
+		words = packet_size;
 	else
 		words = 1;
 
@@ -226,7 +224,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
 {
 	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
 	struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
-	struct omap_pcm_dma_data *dma_data;
+	struct snd_dmaengine_dai_dma_data *dma_data;
 	int wlen, channels, wpf;
 	int pkt_size = 0;
 	unsigned int format, div, framesize, master;
@@ -245,7 +243,6 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 	if (mcbsp->pdata->buffer_size) {
-		dma_data->set_threshold = omap_mcbsp_set_threshold;
 		if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
 			int period_words, max_thrsh;
 			int divider = 0;
@@ -276,9 +273,10 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
 			/* Use packet mode for non mono streams */
 			pkt_size = channels;
 		}
+		omap_mcbsp_set_threshold(substream, pkt_size);
 	}
 
-	dma_data->packet_size = pkt_size;
+	dma_data->maxburst = pkt_size;
 
 	if (mcbsp->configured) {
 		/* McBSP already configured by another stream */
@@ -586,6 +584,10 @@ static struct snd_soc_dai_driver omap_mcbsp_dai = {
 	.ops = &mcbsp_dai_ops,
 };
 
+static const struct snd_soc_component_driver omap_mcbsp_component = {
+	.name		= "omap-mcbsp",
+};
+
 static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
 			struct snd_ctl_elem_info *uinfo)
 {
@@ -793,7 +795,8 @@ static int asoc_mcbsp_probe(struct platform_device *pdev)
 
 	ret = omap_mcbsp_init(pdev);
 	if (!ret)
-		return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai);
+		return snd_soc_register_component(&pdev->dev, &omap_mcbsp_component,
+						  &omap_mcbsp_dai, 1);
 
 	return ret;
 }
@@ -802,7 +805,7 @@ static int asoc_mcbsp_remove(struct platform_device *pdev)
 {
 	struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	if (mcbsp->pdata->ops && mcbsp->pdata->ops->free)
 		mcbsp->pdata->ops->free(mcbsp->id);
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index 5ca11bdac21e..eb05c7ed6d05 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -39,11 +39,14 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
 #include "omap-mcpdm.h"
-#include "omap-pcm.h"
 
-#define OMAP44XX_MCPDM_L3_BASE		0x49032000
+struct mcpdm_link_config {
+	u32 link_mask; /* channel mask for the direction */
+	u32 threshold; /* FIFO threshold */
+};
 
 struct omap_mcpdm {
 	struct device *dev;
@@ -53,29 +56,22 @@ struct omap_mcpdm {
 
 	struct mutex mutex;
 
-	/* channel data */
-	u32 dn_channels;
-	u32 up_channels;
-
-	/* McPDM FIFO thresholds */
-	u32 dn_threshold;
-	u32 up_threshold;
+	/* Playback/Capture configuration */
+	struct mcpdm_link_config config[2];
 
 	/* McPDM dn offsets for rx1, and 2 channels */
 	u32 dn_rx_offset;
+
+	/* McPDM needs to be restarted due to runtime reconfiguration */
+	bool restart;
+
+	struct snd_dmaengine_dai_dma_data dma_data[2];
+	unsigned int dma_req[2];
 };
 
 /*
  * Stream DMA parameters
  */
-static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
-	{
-		.name = "Audio playback",
-	},
-	{
-		.name = "Audio capture",
-	},
-};
 
 static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val)
 {
@@ -130,11 +126,12 @@ static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) {}
 static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
 {
 	u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
+	u32 link_mask = mcpdm->config[0].link_mask | mcpdm->config[1].link_mask;
 
 	ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
 	omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
 
-	ctrl |= mcpdm->dn_channels | mcpdm->up_channels;
+	ctrl |= link_mask;
 	omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
 
 	ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
@@ -148,11 +145,12 @@ static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
 static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm)
 {
 	u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
+	u32 link_mask = MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK;
 
 	ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
 	omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
 
-	ctrl &= ~(mcpdm->dn_channels | mcpdm->up_channels);
+	ctrl &= ~(link_mask);
 	omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
 
 	ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
@@ -188,8 +186,10 @@ static void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm)
 		omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset);
 	}
 
-	omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN, mcpdm->dn_threshold);
-	omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP, mcpdm->up_threshold);
+	omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN,
+			 mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold);
+	omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP,
+			 mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold);
 
 	omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_SET,
 			MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE);
@@ -267,7 +267,7 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
 	mutex_unlock(&mcpdm->mutex);
 
 	snd_soc_dai_set_dma_data(dai, substream,
-				 &omap_mcpdm_dai_dma_params[substream->stream]);
+				 &mcpdm->dma_data[substream->stream]);
 
 	return 0;
 }
@@ -283,6 +283,8 @@ static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
 		if (omap_mcpdm_active(mcpdm)) {
 			omap_mcpdm_stop(mcpdm);
 			omap_mcpdm_close_streams(mcpdm);
+			mcpdm->config[0].link_mask = 0;
+			mcpdm->config[1].link_mask = 0;
 		}
 	}
 
@@ -295,7 +297,8 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
 {
 	struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
 	int stream = substream->stream;
-	struct omap_pcm_dma_data *dma_data;
+	struct snd_dmaengine_dai_dma_data *dma_data;
+	u32 threshold;
 	int channels;
 	int link_mask = 0;
 
@@ -325,16 +328,32 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
 
 	dma_data = snd_soc_dai_get_dma_data(dai, substream);
 
+	threshold = mcpdm->config[stream].threshold;
 	/* Configure McPDM channels, and DMA packet size */
 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		mcpdm->dn_channels = link_mask << 3;
-		dma_data->packet_size =
-			(MCPDM_DN_THRES_MAX - mcpdm->dn_threshold) * channels;
+		link_mask <<= 3;
+
+		/* If capture is not running assume a stereo stream to come */
+		if (!mcpdm->config[!stream].link_mask)
+			mcpdm->config[!stream].link_mask = 0x3;
+
+		dma_data->maxburst =
+				(MCPDM_DN_THRES_MAX - threshold) * channels;
 	} else {
-		mcpdm->up_channels = link_mask << 0;
-		dma_data->packet_size = mcpdm->up_threshold * channels;
+		/* If playback is not running assume a stereo stream to come */
+		if (!mcpdm->config[!stream].link_mask)
+			mcpdm->config[!stream].link_mask = (0x3 << 3);
+
+		dma_data->maxburst = threshold * channels;
 	}
 
+	/* Check if we need to restart McPDM with this stream */
+	if (mcpdm->config[stream].link_mask &&
+	    mcpdm->config[stream].link_mask != link_mask)
+		mcpdm->restart = true;
+
+	mcpdm->config[stream].link_mask = link_mask;
+
 	return 0;
 }
 
@@ -346,6 +365,11 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream,
 	if (!omap_mcpdm_active(mcpdm)) {
 		omap_mcpdm_start(mcpdm);
 		omap_mcpdm_reg_dump(mcpdm);
+	} else if (mcpdm->restart) {
+		omap_mcpdm_stop(mcpdm);
+		omap_mcpdm_start(mcpdm);
+		mcpdm->restart = false;
+		omap_mcpdm_reg_dump(mcpdm);
 	}
 
 	return 0;
@@ -369,7 +393,7 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai)
 	pm_runtime_get_sync(mcpdm->dev);
 	omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00);
 
-	ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler,
+	ret = devm_request_irq(mcpdm->dev, mcpdm->irq, omap_mcpdm_irq_handler,
 				0, "McPDM", (void *)mcpdm);
 
 	pm_runtime_put_sync(mcpdm->dev);
@@ -380,8 +404,9 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai)
 	}
 
 	/* Configure McPDM threshold values */
-	mcpdm->dn_threshold = 2;
-	mcpdm->up_threshold = MCPDM_UP_THRES_MAX - 3;
+	mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold = 2;
+	mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold =
+							MCPDM_UP_THRES_MAX - 3;
 	return ret;
 }
 
@@ -389,7 +414,6 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai)
 {
 	struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
 
-	free_irq(mcpdm->irq, (void *)mcpdm);
 	pm_runtime_disable(mcpdm->dev);
 
 	return 0;
@@ -420,6 +444,10 @@ static struct snd_soc_dai_driver omap_mcpdm_dai = {
 	.ops = &omap_mcpdm_dai_ops,
 };
 
+static const struct snd_soc_component_driver omap_mcpdm_component = {
+	.name		= "omap-mcpdm",
+};
+
 void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd,
 				    u8 rx1, u8 rx2)
 {
@@ -446,33 +474,30 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
 	if (res == NULL)
 		return -ENOMEM;
 
-	omap_mcpdm_dai_dma_params[0].port_addr = res->start + MCPDM_REG_DN_DATA;
-	omap_mcpdm_dai_dma_params[1].port_addr = res->start + MCPDM_REG_UP_DATA;
+	mcpdm->dma_data[0].addr = res->start + MCPDM_REG_DN_DATA;
+	mcpdm->dma_data[1].addr = res->start + MCPDM_REG_UP_DATA;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "dn_link");
 	if (!res)
 		return -ENODEV;
 
-	omap_mcpdm_dai_dma_params[0].dma_req = res->start;
+	mcpdm->dma_req[0] = res->start;
+	mcpdm->dma_data[0].filter_data = &mcpdm->dma_req[0];
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "up_link");
 	if (!res)
 		return -ENODEV;
 
-	omap_mcpdm_dai_dma_params[1].dma_req = res->start;
+	mcpdm->dma_req[1] = res->start;
+	mcpdm->dma_data[1].filter_data = &mcpdm->dma_req[1];
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
 	if (res == NULL)
 		return -ENOMEM;
 
-	if (!devm_request_mem_region(&pdev->dev, res->start,
-				     resource_size(res), "McPDM"))
-		return -EBUSY;
-
-	mcpdm->io_base = devm_ioremap(&pdev->dev, res->start,
-				      resource_size(res));
-	if (!mcpdm->io_base)
-		return -ENOMEM;
+	mcpdm->io_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(mcpdm->io_base))
+		return PTR_ERR(mcpdm->io_base);
 
 	mcpdm->irq = platform_get_irq(pdev, 0);
 	if (mcpdm->irq < 0)
@@ -480,12 +505,13 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
 
 	mcpdm->dev = &pdev->dev;
 
-	return snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
+	return snd_soc_register_component(&pdev->dev, &omap_mcpdm_component,
+					  &omap_mcpdm_dai, 1);
 }
 
 static int asoc_mcpdm_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	return 0;
 }
 
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index c722c2ef9665..c28e042f2208 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -32,8 +32,6 @@
 #include <sound/dmaengine_pcm.h>
 #include <sound/soc.h>
 
-#include "omap-pcm.h"
-
 #ifdef CONFIG_ARCH_OMAP1
 #define pcm_omap1510()	cpu_is_omap1510()
 #else
@@ -56,25 +54,6 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {
 	.buffer_bytes_max	= 128 * 1024,
 };
 
-static int omap_pcm_get_dma_buswidth(int num_bits)
-{
-	int buswidth;
-
-	switch (num_bits) {
-	case 16:
-		buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
-		break;
-	case 32:
-		buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
-		break;
-	default:
-		buswidth = -EINVAL;
-		break;
-	}
-	return buswidth;
-}
-
-
 /* this may get called several times by oss emulation */
 static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
 			      struct snd_pcm_hw_params *params)
@@ -105,20 +84,9 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
 	if (err)
 		return err;
 
-	/* Override the *_dma addr_width if requested by the DAI driver */
-	if (dma_data->data_type) {
-		int buswidth = omap_pcm_get_dma_buswidth(dma_data->data_type);
-
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			config.dst_addr_width = buswidth;
-		else
-			config.src_addr_width = buswidth;
-	}
-
-	config.src_addr = dma_data->port_addr;
-	config.dst_addr = dma_data->port_addr;
-	config.src_maxburst = dma_data->packet_size;
-	config.dst_maxburst = dma_data->packet_size;
+	snd_dmaengine_pcm_set_config_from_dai_data(substream,
+			snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
+			&config);
 
 	return dmaengine_slave_config(chan, &config);
 }
@@ -129,37 +97,6 @@ static int omap_pcm_hw_free(struct snd_pcm_substream *substream)
 	return 0;
 }
 
-static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct omap_pcm_dma_data *dma_data;
-	int ret = 0;
-
-	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_RESUME:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		/* Configure McBSP internal buffer usage */
-		if (dma_data->set_threshold)
-			dma_data->set_threshold(substream);
-		break;
-
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		break;
-	default:
-		ret = -EINVAL;
-	}
-
-	if (ret == 0)
-		ret = snd_dmaengine_pcm_trigger(substream, cmd);
-
-	return ret;
-}
-
 static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
 {
 	snd_pcm_uframes_t offset;
@@ -175,20 +112,15 @@ static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
 static int omap_pcm_open(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct omap_pcm_dma_data *dma_data;
+	struct snd_dmaengine_dai_dma_data *dma_data;
 
 	snd_soc_set_runtime_hwparams(substream, &omap_pcm_hardware);
 
 	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
-	return snd_dmaengine_pcm_open(substream, omap_dma_filter_fn,
-				      &dma_data->dma_req);
-}
-
-static int omap_pcm_close(struct snd_pcm_substream *substream)
-{
-	snd_dmaengine_pcm_close(substream);
-	return 0;
+	return snd_dmaengine_pcm_open_request_chan(substream,
+						   omap_dma_filter_fn,
+						   dma_data->filter_data);
 }
 
 static int omap_pcm_mmap(struct snd_pcm_substream *substream,
@@ -204,11 +136,11 @@ static int omap_pcm_mmap(struct snd_pcm_substream *substream,
 
 static struct snd_pcm_ops omap_pcm_ops = {
 	.open		= omap_pcm_open,
-	.close		= omap_pcm_close,
+	.close		= snd_dmaengine_pcm_close_release_chan,
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= omap_pcm_hw_params,
 	.hw_free	= omap_pcm_hw_free,
-	.trigger	= omap_pcm_trigger,
+	.trigger	= snd_dmaengine_pcm_trigger,
 	.pointer	= omap_pcm_pointer,
 	.mmap		= omap_pcm_mmap,
 };
diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h
deleted file mode 100644
index cabe74c4068b..000000000000
--- a/sound/soc/omap/omap-pcm.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * omap-pcm.h
- *
- * Copyright (C) 2008 Nokia Corporation
- *
- * Contact: Jarkko Nikula <jarkko.nikula@bitmer.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
- * 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
- *
- */
-
-#ifndef __OMAP_PCM_H__
-#define __OMAP_PCM_H__
-
-struct snd_pcm_substream;
-
-struct omap_pcm_dma_data {
-	char		*name;		/* stream identifier */
-	int		dma_req;	/* DMA request line */
-	unsigned long	port_addr;	/* transmit/receive register */
-	void (*set_threshold)(struct snd_pcm_substream *substream);
-	int		data_type;	/* 8, 16, 32 (bits) or 0 to let omap-pcm
-					 * to decide the sDMA data type */
-	int		packet_size;	/* packet size only in PACKET mode */
-};
-
-#endif
diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c
index fd98509d0f49..2a9324f794d8 100644
--- a/sound/soc/omap/omap-twl4030.c
+++ b/sound/soc/omap/omap-twl4030.c
@@ -43,7 +43,6 @@
 #include <sound/jack.h>
 
 #include "omap-mcbsp.h"
-#include "omap-pcm.h"
 
 struct omap_twl4030 {
 	int jack_detect;	/* board can detect jack events */
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c
index 805512f2555a..cf604a2faa18 100644
--- a/sound/soc/omap/omap3pandora.c
+++ b/sound/soc/omap/omap3pandora.c
@@ -34,7 +34,6 @@
 #include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include "omap-mcbsp.h"
-#include "omap-pcm.h"
 
 #define OMAP3_PANDORA_DAC_POWER_GPIO	118
 #define OMAP3_PANDORA_AMP_POWER_GPIO	14
@@ -80,12 +79,18 @@ static int omap3pandora_hw_params(struct snd_pcm_substream *substream,
 static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *k, int event)
 {
+	int ret;
+
 	/*
 	 * The PCM1773 DAC datasheet requires 1ms delay between switching
 	 * VCC power on/off and /PD pin high/low
 	 */
 	if (SND_SOC_DAPM_EVENT_ON(event)) {
-		regulator_enable(omap3pandora_dac_reg);
+		ret = regulator_enable(omap3pandora_dac_reg);
+		if (ret) {
+			dev_err(w->dapm->dev, "Failed to power DAC: %d\n", ret);
+			return ret;
+		}
 		mdelay(1);
 		gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1);
 	} else {
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
index 06ef8d67ed1c..d03e57da7708 100644
--- a/sound/soc/omap/osk5912.c
+++ b/sound/soc/omap/osk5912.c
@@ -33,7 +33,6 @@
 #include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include "omap-mcbsp.h"
-#include "omap-pcm.h"
 #include "../codecs/tlv320aic23.h"
 
 #define CODEC_CLOCK 	12000000
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 3cd525748975..249cd230ad8f 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -37,7 +37,6 @@
 #include <asm/mach-types.h>
 
 #include "omap-mcbsp.h"
-#include "omap-pcm.h"
 
 #define RX51_TVOUT_SEL_GPIO		40
 #define RX51_JACK_DETECT_GPIO		177
diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c
index 190eb0bccf5f..349930015264 100644
--- a/sound/soc/pxa/mmp-pcm.c
+++ b/sound/soc/pxa/mmp-pcm.c
@@ -118,9 +118,8 @@ static int mmp_pcm_open(struct snd_pcm_substream *substream)
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct platform_device *pdev = to_platform_device(rtd->platform->dev);
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct mmp_dma_data *dma_data;
+	struct mmp_dma_data dma_data;
 	struct resource *r;
-	int ret;
 
 	r = platform_get_resource(pdev, IORESOURCE_DMA, substream->stream);
 	if (!r)
@@ -128,33 +127,12 @@ static int mmp_pcm_open(struct snd_pcm_substream *substream)
 
 	snd_soc_set_runtime_hwparams(substream,
 				&mmp_pcm_hardware[substream->stream]);
-	dma_data = devm_kzalloc(&pdev->dev,
-			sizeof(struct mmp_dma_data), GFP_KERNEL);
-	if (dma_data == NULL)
-		return -ENOMEM;
 
-	dma_data->dma_res = r;
-	dma_data->ssp_id = cpu_dai->id;
+	dma_data.dma_res = r;
+	dma_data.ssp_id = cpu_dai->id;
 
-	ret = snd_dmaengine_pcm_open(substream, filter, dma_data);
-	if (ret) {
-		devm_kfree(&pdev->dev, dma_data);
-		return ret;
-	}
-
-	snd_dmaengine_pcm_set_data(substream, dma_data);
-	return 0;
-}
-
-static int mmp_pcm_close(struct snd_pcm_substream *substream)
-{
-	struct mmp_dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct platform_device *pdev = to_platform_device(rtd->platform->dev);
-
-	snd_dmaengine_pcm_close(substream);
-	devm_kfree(&pdev->dev, dma_data);
-	return 0;
+	return snd_dmaengine_pcm_open_request_chan(substream, filter,
+		    &dma_data);
 }
 
 static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
@@ -171,7 +149,7 @@ static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
 
 struct snd_pcm_ops mmp_pcm_ops = {
 	.open		= mmp_pcm_open,
-	.close		= mmp_pcm_close,
+	.close		= snd_dmaengine_pcm_close_release_chan,
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= mmp_pcm_hw_params,
 	.trigger	= snd_dmaengine_pcm_trigger,
diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c
index 9140c4abafbc..a64779980177 100644
--- a/sound/soc/pxa/mmp-sspa.c
+++ b/sound/soc/pxa/mmp-sspa.c
@@ -405,6 +405,10 @@ struct snd_soc_dai_driver mmp_sspa_dai = {
 	.ops = &mmp_sspa_dai_ops,
 };
 
+static const struct snd_soc_component_driver mmp_sspa_component = {
+	.name		= "mmp-sspa",
+};
+
 static int asoc_mmp_sspa_probe(struct platform_device *pdev)
 {
 	struct sspa_priv *priv;
@@ -450,7 +454,8 @@ static int asoc_mmp_sspa_probe(struct platform_device *pdev)
 	priv->dai_fmt = (unsigned int) -1;
 	platform_set_drvdata(pdev, priv);
 
-	return snd_soc_register_dai(&pdev->dev, &mmp_sspa_dai);
+	return snd_soc_register_component(&pdev->dev, &mmp_sspa_component,
+					  &mmp_sspa_dai, 1);
 }
 
 static int asoc_mmp_sspa_remove(struct platform_device *pdev)
@@ -460,7 +465,7 @@ static int asoc_mmp_sspa_remove(struct platform_device *pdev)
 	clk_disable(priv->audio_clk);
 	clk_put(priv->audio_clk);
 	clk_put(priv->sysclk);
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	return 0;
 }
 
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index d3eb0c2eec77..6f4dd7543e82 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -794,14 +794,19 @@ static struct snd_soc_dai_driver pxa_ssp_dai = {
 		.ops = &pxa_ssp_dai_ops,
 };
 
+static const struct snd_soc_component_driver pxa_ssp_component = {
+	.name		= "pxa-ssp",
+};
+
 static int asoc_ssp_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_dai(&pdev->dev, &pxa_ssp_dai);
+	return snd_soc_register_component(&pdev->dev, &pxa_ssp_component,
+					  &pxa_ssp_dai, 1);
 }
 
 static int asoc_ssp_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	return 0;
 }
 
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index 4b0a009bd683..57ea8e6c5488 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -47,6 +47,7 @@ struct snd_ac97_bus_ops soc_ac97_ops = {
 	.warm_reset	= pxa2xx_ac97_warm_reset,
 	.reset	= pxa2xx_ac97_cold_reset,
 };
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
 static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_out = {
 	.name			= "AC97 PCM Stereo out",
@@ -232,7 +233,9 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = {
 },
 };
 
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
+static const struct snd_soc_component_driver pxa_ac97_component = {
+	.name		= "pxa-ac97",
+};
 
 static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
 {
@@ -245,13 +248,13 @@ static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
 	 * driver to do interesting things with the clocking to get us up
 	 * and running.
 	 */
-	return snd_soc_register_dais(&pdev->dev, pxa_ac97_dai_driver,
-			ARRAY_SIZE(pxa_ac97_dai_driver));
+	return snd_soc_register_component(&pdev->dev, &pxa_ac97_component,
+					  pxa_ac97_dai_driver, ARRAY_SIZE(pxa_ac97_dai_driver));
 }
 
 static int pxa2xx_ac97_dev_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(pxa_ac97_dai_driver));
+	snd_soc_unregister_component(&pdev->dev);
 	return 0;
 }
 
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index 6b1a06f67564..f7ca71664112 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -360,14 +360,19 @@ static struct snd_soc_dai_driver pxa_i2s_dai = {
 	.symmetric_rates = 1,
 };
 
+static const struct snd_soc_component_driver pxa_i2s_component = {
+	.name		= "pxa-i2s",
+};
+
 static int pxa2xx_i2s_drv_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_dai(&pdev->dev, &pxa_i2s_dai);
+	return snd_soc_register_component(&pdev->dev, &pxa_i2s_component,
+					  &pxa_i2s_dai, 1);
 }
 
 static int pxa2xx_i2s_drv_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	return 0;
 }
 
diff --git a/sound/soc/s6000/s6000-i2s.c b/sound/soc/s6000/s6000-i2s.c
index fee4d477a49c..73bb99f0109a 100644
--- a/sound/soc/s6000/s6000-i2s.c
+++ b/sound/soc/s6000/s6000-i2s.c
@@ -436,6 +436,10 @@ static struct snd_soc_dai_driver s6000_i2s_dai = {
 	.ops = &s6000_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver s6000_i2s_component = {
+	.name		= "s6000-i2s",
+};
+
 static int s6000_i2s_probe(struct platform_device *pdev)
 {
 	struct s6000_i2s_dev *dev;
@@ -543,7 +547,8 @@ static int s6000_i2s_probe(struct platform_device *pdev)
 			 S6_I2S_INT_UNDERRUN |
 			 S6_I2S_INT_OVERRUN);
 
-	ret = snd_soc_register_dai(&pdev->dev, &s6000_i2s_dai);
+	ret = snd_soc_register_component(&pdev->dev, &s6000_i2s_component,
+					 &s6000_i2s_dai, 1);
 	if (ret)
 		goto err_release_dev;
 
@@ -572,7 +577,7 @@ static void s6000_i2s_remove(struct platform_device *pdev)
 	struct resource *region;
 	void __iomem *mmio = dev->scbbase;
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	s6000_i2s_stop_channel(dev, 0);
 	s6000_i2s_stop_channel(dev, 1);
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index 90e7e6653233..475fb0d8b3c6 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -35,11 +35,10 @@ config SND_SAMSUNG_I2S
 	tristate
 
 config SND_SOC_SAMSUNG_NEO1973_WM8753
-	tristate "Audio support for Openmoko Neo1973 Smartphones (GTA01/GTA02)"
-	depends on SND_SOC_SAMSUNG && (MACH_NEO1973_GTA01 || MACH_NEO1973_GTA02)
+	tristate "Audio support for Openmoko Neo1973 Smartphones (GTA02)"
+	depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA02
 	select SND_S3C24XX_I2S
 	select SND_SOC_WM8753
-	select SND_SOC_LM4857 if MACH_NEO1973_GTA01
 	select SND_SOC_DFBMCS320
 	help
 	  Say Y here to enable audio support for the Openmoko Neo1973
diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c
index 0df3c5644cfa..cb88ead98917 100644
--- a/sound/soc/samsung/ac97.c
+++ b/sound/soc/samsung/ac97.c
@@ -20,7 +20,7 @@
 #include <sound/soc.h>
 
 #include <mach/dma.h>
-#include <plat/regs-ac97.h>
+#include "regs-ac97.h"
 #include <linux/platform_data/asoc-s3c.h>
 
 #include "dma.h"
@@ -370,6 +370,10 @@ static struct snd_soc_dai_driver s3c_ac97_dai[] = {
 	},
 };
 
+static const struct snd_soc_component_driver s3c_ac97_component = {
+	.name		= "s3c-ac97",
+};
+
 static int s3c_ac97_probe(struct platform_device *pdev)
 {
 	struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res;
@@ -457,8 +461,8 @@ static int s3c_ac97_probe(struct platform_device *pdev)
 		goto err4;
 	}
 
-	ret = snd_soc_register_dais(&pdev->dev, s3c_ac97_dai,
-			ARRAY_SIZE(s3c_ac97_dai));
+	ret = snd_soc_register_component(&pdev->dev, &s3c_ac97_component,
+					 s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
 	if (ret)
 		goto err5;
 
@@ -470,7 +474,7 @@ static int s3c_ac97_probe(struct platform_device *pdev)
 
 	return 0;
 err6:
-	snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai));
+	snd_soc_unregister_component(&pdev->dev);
 err5:
 	free_irq(irq_res->start, NULL);
 err4:
@@ -490,7 +494,7 @@ static int s3c_ac97_remove(struct platform_device *pdev)
 	struct resource *mem_res, *irq_res;
 
 	asoc_dma_platform_unregister(&pdev->dev);
-	snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai));
+	snd_soc_unregister_component(&pdev->dev);
 
 	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (irq_res)
diff --git a/sound/soc/samsung/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c
index d37ede58e0a8..415ad81999c4 100644
--- a/sound/soc/samsung/goni_wm8994.c
+++ b/sound/soc/samsung/goni_wm8994.c
@@ -218,6 +218,10 @@ static struct snd_soc_dai_driver voice_dai = {
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
 };
 
+static const struct snd_soc_component_driver voice_component = {
+	.name		= "goni-voice",
+};
+
 static struct snd_soc_ops goni_voice_ops = {
 	.hw_params = goni_voice_hw_params,
 };
@@ -270,7 +274,8 @@ static int __init goni_init(void)
 		return -ENOMEM;
 
 	/* register voice DAI here */
-	ret = snd_soc_register_dai(&goni_snd_device->dev, &voice_dai);
+	ret = snd_soc_register_component(&goni_snd_device->dev, &voice_component,
+					 &voice_dai, 1);
 	if (ret) {
 		platform_device_put(goni_snd_device);
 		return ret;
@@ -280,7 +285,7 @@ static int __init goni_init(void)
 	ret = platform_device_add(goni_snd_device);
 
 	if (ret) {
-		snd_soc_unregister_dai(&goni_snd_device->dev);
+		snd_soc_unregister_component(&goni_snd_device->dev);
 		platform_device_put(goni_snd_device);
 	}
 
@@ -289,7 +294,7 @@ static int __init goni_init(void)
 
 static void __exit goni_exit(void)
 {
-	snd_soc_unregister_dai(&goni_snd_device->dev);
+	snd_soc_unregister_component(&goni_snd_device->dev);
 	platform_device_unregister(goni_snd_device);
 }
 
diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c
index 15a3817aa5c8..fa91376e323d 100644
--- a/sound/soc/samsung/h1940_uda1380.c
+++ b/sound/soc/samsung/h1940_uda1380.c
@@ -20,7 +20,7 @@
 #include <sound/soc.h>
 #include <sound/jack.h>
 
-#include <plat/regs-iis.h>
+#include "regs-iis.h"
 #include <asm/mach-types.h>
 
 #include "s3c24xx-i2s.h"
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 6bbeb0bf1a73..82ebb1a51479 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -963,6 +963,10 @@ static const struct snd_soc_dai_ops samsung_i2s_dai_ops = {
 	.delay = i2s_delay,
 };
 
+static const struct snd_soc_component_driver samsung_i2s_component = {
+	.name		= "samsung-i2s",
+};
+
 #define SAMSUNG_I2S_RATES	SNDRV_PCM_RATE_8000_96000
 
 #define SAMSUNG_I2S_FMTS	(SNDRV_PCM_FMTBIT_S8 | \
@@ -1114,8 +1118,9 @@ static int samsung_i2s_probe(struct platform_device *pdev)
 			dev_err(&pdev->dev, "Unable to get drvdata\n");
 			return -EFAULT;
 		}
-		snd_soc_register_dai(&sec_dai->pdev->dev,
-			&sec_dai->i2s_dai_drv);
+		snd_soc_register_component(&sec_dai->pdev->dev,
+					   &samsung_i2s_component,
+					   &sec_dai->i2s_dai_drv, 1);
 		asoc_dma_platform_register(&pdev->dev);
 		return 0;
 	}
@@ -1244,7 +1249,8 @@ static int samsung_i2s_probe(struct platform_device *pdev)
 		}
 	}
 
-	snd_soc_register_dai(&pri_dai->pdev->dev, &pri_dai->i2s_dai_drv);
+	snd_soc_register_component(&pri_dai->pdev->dev, &samsung_i2s_component,
+				   &pri_dai->i2s_dai_drv, 1);
 
 	pm_runtime_enable(&pdev->dev);
 
@@ -1283,7 +1289,7 @@ static int samsung_i2s_remove(struct platform_device *pdev)
 	i2s->sec_dai = NULL;
 
 	asoc_dma_platform_unregister(&pdev->dev);
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	return 0;
 }
@@ -1298,7 +1304,7 @@ static struct platform_device_id samsung_i2s_driver_ids[] = {
 	},
 	{},
 };
-MODULE_DEVICE_TABLE(platform, samsung-i2s-driver-ids);
+MODULE_DEVICE_TABLE(platform, samsung_i2s_driver_ids);
 
 #ifdef CONFIG_OF
 static struct samsung_i2s_dai_data samsung_i2s_dai_data_array[] = {
diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c
index a07950b0c8ce..6e5fed30aa27 100644
--- a/sound/soc/samsung/idma.c
+++ b/sound/soc/samsung/idma.c
@@ -68,6 +68,8 @@ static struct idma_info {
 	dma_addr_t	lp_tx_addr;
 } idma;
 
+static int idma_irq;
+
 static void idma_getpos(dma_addr_t *src)
 {
 	*src = idma.lp_tx_addr +
@@ -305,7 +307,7 @@ static int idma_open(struct snd_pcm_substream *substream)
 	if (prtd == NULL)
 		return -ENOMEM;
 
-	ret = request_irq(IRQ_I2S0, iis_irq, 0, "i2s", prtd);
+	ret = request_irq(idma_irq, iis_irq, 0, "i2s", prtd);
 	if (ret < 0) {
 		pr_err("fail to claim i2s irq , ret = %d\n", ret);
 		kfree(prtd);
@@ -324,7 +326,7 @@ static int idma_close(struct snd_pcm_substream *substream)
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct idma_ctrl *prtd = runtime->private_data;
 
-	free_irq(IRQ_I2S0, prtd);
+	free_irq(idma_irq, prtd);
 
 	if (!prtd)
 		pr_err("idma_close called with prtd == NULL\n");
@@ -409,6 +411,7 @@ void idma_reg_addr_init(void __iomem *regs, dma_addr_t addr)
 	idma.regs = regs;
 	idma.lp_tx_addr = addr;
 }
+EXPORT_SYMBOL_GPL(idma_reg_addr_init);
 
 static struct snd_soc_platform_driver asoc_idma_platform = {
 	.ops = &idma_ops,
@@ -418,6 +421,10 @@ static struct snd_soc_platform_driver asoc_idma_platform = {
 
 static int asoc_idma_platform_probe(struct platform_device *pdev)
 {
+	idma_irq = platform_get_irq(pdev, 0);
+	if (idma_irq < 0)
+		return idma_irq;
+
 	return snd_soc_register_platform(&pdev->dev, &asoc_idma_platform);
 }
 
diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c
index a301d8cfaa34..e591c386917a 100644
--- a/sound/soc/samsung/neo1973_wm8753.c
+++ b/sound/soc/samsung/neo1973_wm8753.c
@@ -21,8 +21,7 @@
 #include <sound/soc.h>
 
 #include <asm/mach-types.h>
-#include <plat/regs-iis.h>
-#include <mach/gta02.h>
+#include "regs-iis.h"
 
 #include "../codecs/wm8753.h"
 #include "s3c24xx-i2s.h"
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c
index 13bab79ad93d..1566afe9ef52 100644
--- a/sound/soc/samsung/pcm.c
+++ b/sound/soc/samsung/pcm.c
@@ -490,6 +490,10 @@ static struct snd_soc_dai_driver s3c_pcm_dai[] = {
 	},
 };
 
+static const struct snd_soc_component_driver s3c_pcm_component = {
+	.name		= "s3c-pcm",
+};
+
 static int s3c_pcm_dev_probe(struct platform_device *pdev)
 {
 	struct s3c_pcm_info *pcm;
@@ -583,7 +587,8 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
 
 	pm_runtime_enable(&pdev->dev);
 
-	ret = snd_soc_register_dai(&pdev->dev, &s3c_pcm_dai[pdev->id]);
+	ret = snd_soc_register_component(&pdev->dev, &s3c_pcm_component,
+					 &s3c_pcm_dai[pdev->id], 1);
 	if (ret != 0) {
 		dev_err(&pdev->dev, "failed to get register DAI: %d\n", ret);
 		goto err5;
@@ -598,7 +603,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
 	return 0;
 
 err6:
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 err5:
 	clk_disable_unprepare(pcm->pclk);
 	clk_put(pcm->pclk);
@@ -619,7 +624,7 @@ static int s3c_pcm_dev_remove(struct platform_device *pdev)
 	struct resource *mem_res;
 
 	asoc_dma_platform_unregister(&pdev->dev);
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	pm_runtime_disable(&pdev->dev);
 
diff --git a/arch/arm/plat-samsung/include/plat/regs-ac97.h b/sound/soc/samsung/regs-ac97.h
index c3878f7acb83..c3878f7acb83 100644
--- a/arch/arm/plat-samsung/include/plat/regs-ac97.h
+++ b/sound/soc/samsung/regs-ac97.h
diff --git a/arch/arm/plat-samsung/include/plat/regs-iis.h b/sound/soc/samsung/regs-iis.h
index a18d35e7a735..a18d35e7a735 100644
--- a/arch/arm/plat-samsung/include/plat/regs-iis.h
+++ b/sound/soc/samsung/regs-iis.h
diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c
index a5826ea9cad6..704460a37005 100644
--- a/sound/soc/samsung/rx1950_uda1380.c
+++ b/sound/soc/samsung/rx1950_uda1380.c
@@ -24,7 +24,7 @@
 #include <sound/soc.h>
 #include <sound/jack.h>
 
-#include <plat/regs-iis.h>
+#include "regs-iis.h"
 #include <asm/mach-types.h>
 
 #include "s3c24xx-i2s.h"
diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c
index 7a73380b3560..20e98d1dded2 100644
--- a/sound/soc/samsung/s3c-i2s-v2.c
+++ b/sound/soc/samsung/s3c-i2s-v2.c
@@ -731,8 +731,9 @@ static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
 #define s3c2412_i2s_resume  NULL
 #endif
 
-int s3c_i2sv2_register_dai(struct device *dev, int id,
-		struct snd_soc_dai_driver *drv)
+int s3c_i2sv2_register_component(struct device *dev, int id,
+			   struct snd_soc_component_driver *cmp_drv,
+			   struct snd_soc_dai_driver *dai_drv)
 {
 	struct snd_soc_dai_ops *ops = drv->ops;
 
@@ -750,8 +751,8 @@ int s3c_i2sv2_register_dai(struct device *dev, int id,
 	drv->suspend = s3c2412_i2s_suspend;
 	drv->resume = s3c2412_i2s_resume;
 
-	return snd_soc_register_dai(dev, drv);
+	return snd_soc_register_component(dev, cmp_drv, dai_drv, 1);
 }
-EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai);
+EXPORT_SYMBOL_GPL(s3c_i2sv2_register_component);
 
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/s3c-i2s-v2.h b/sound/soc/samsung/s3c-i2s-v2.h
index f8297d9bb8a3..90abab364b49 100644
--- a/sound/soc/samsung/s3c-i2s-v2.h
+++ b/sound/soc/samsung/s3c-i2s-v2.h
@@ -92,7 +92,7 @@ extern int s3c_i2sv2_probe(struct snd_soc_dai *dai,
 			   unsigned long base);
 
 /**
- * s3c_i2sv2_register_dai - register dai with soc core
+ * s3c_i2sv2_register_component - register component and dai with soc core
  * @dev: DAI device
  * @id: DAI ID
  * @drv: The driver structure to register
@@ -100,7 +100,8 @@ extern int s3c_i2sv2_probe(struct snd_soc_dai *dai,
  * Fill in any missing fields and then register the given dai with the
  * soc core.
  */
-extern int s3c_i2sv2_register_dai(struct device *dev, int id,
-		struct snd_soc_dai_driver *drv);
+extern int s3c_i2sv2_register_component(struct device *dev, int id,
+					struct snd_soc_component_driver *cmp_drv,
+					struct snd_soc_dai_driver *dai_drv);
 
 #endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */
diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c
index 221337716393..47e23864ea72 100644
--- a/sound/soc/samsung/s3c2412-i2s.c
+++ b/sound/soc/samsung/s3c2412-i2s.c
@@ -160,11 +160,17 @@ static struct snd_soc_dai_driver s3c2412_i2s_dai = {
 	.ops = &s3c2412_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver s3c2412_i2s_component = {
+	.name		= "s3c2412-i2s",
+};
+
 static int s3c2412_iis_dev_probe(struct platform_device *pdev)
 {
 	int ret = 0;
 
-	ret = s3c_i2sv2_register_dai(&pdev->dev, -1, &s3c2412_i2s_dai);
+	ret = s3c_i2sv2_register_component(&pdev->dev, -1,
+					   &s3c2412_i2s_component,
+					   &s3c2412_i2s_dai);
 	if (ret) {
 		pr_err("failed to register the dai\n");
 		return ret;
@@ -178,14 +184,14 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev)
 
 	return 0;
 err:
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	return ret;
 }
 
 static int s3c2412_iis_dev_remove(struct platform_device *pdev)
 {
 	asoc_dma_platform_unregister(&pdev->dev);
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	return 0;
 }
 
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c
index 13f6dd1ceb00..8b3414551a62 100644
--- a/sound/soc/samsung/s3c24xx-i2s.c
+++ b/sound/soc/samsung/s3c24xx-i2s.c
@@ -24,7 +24,7 @@
 #include <sound/pcm_params.h>
 
 #include <mach/dma.h>
-#include <plat/regs-iis.h>
+#include "regs-iis.h"
 
 #include "dma.h"
 #include "s3c24xx-i2s.h"
@@ -465,11 +465,16 @@ static struct snd_soc_dai_driver s3c24xx_i2s_dai = {
 	.ops = &s3c24xx_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver s3c24xx_i2s_component = {
+	.name		= "s3c24xx-i2s",
+};
+
 static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
 {
 	int ret = 0;
 
-	ret = snd_soc_register_dai(&pdev->dev, &s3c24xx_i2s_dai);
+	ret = snd_soc_register_component(&pdev->dev, &s3c24xx_i2s_component,
+					 &s3c24xx_i2s_dai, 1);
 	if (ret) {
 		pr_err("failed to register the dai\n");
 		return ret;
@@ -483,14 +488,14 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
 
 	return 0;
 err:
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	return ret;
 }
 
 static int s3c24xx_iis_dev_remove(struct platform_device *pdev)
 {
 	asoc_dma_platform_unregister(&pdev->dev);
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	return 0;
 }
 
diff --git a/sound/soc/samsung/s3c24xx_uda134x.c b/sound/soc/samsung/s3c24xx_uda134x.c
index 333e1b7f06c7..1b7b52b0af97 100644
--- a/sound/soc/samsung/s3c24xx_uda134x.c
+++ b/sound/soc/samsung/s3c24xx_uda134x.c
@@ -18,7 +18,7 @@
 #include <sound/soc.h>
 #include <sound/s3c24xx_uda134x.h>
 
-#include <plat/regs-iis.h>
+#include "regs-iis.h"
 
 #include "s3c24xx-i2s.h"
 
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c
index 5008e5bd6ed8..2e5ebb2f1982 100644
--- a/sound/soc/samsung/spdif.c
+++ b/sound/soc/samsung/spdif.c
@@ -357,6 +357,10 @@ static struct snd_soc_dai_driver samsung_spdif_dai = {
 	.resume = spdif_resume,
 };
 
+static const struct snd_soc_component_driver samsung_spdif_component = {
+	.name		= "samsung-spdif",
+};
+
 static int spdif_probe(struct platform_device *pdev)
 {
 	struct s3c_audio_pdata *spdif_pdata;
@@ -424,7 +428,8 @@ static int spdif_probe(struct platform_device *pdev)
 
 	dev_set_drvdata(&pdev->dev, spdif);
 
-	ret = snd_soc_register_dai(&pdev->dev, &samsung_spdif_dai);
+	ret = snd_soc_register_component(&pdev->dev, &samsung_spdif_component,
+					 &samsung_spdif_dai, 1);
 	if (ret != 0) {
 		dev_err(&pdev->dev, "fail to register dai\n");
 		goto err4;
@@ -445,7 +450,7 @@ static int spdif_probe(struct platform_device *pdev)
 
 	return 0;
 err5:
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 err4:
 	iounmap(spdif->regs);
 err3:
@@ -466,7 +471,7 @@ static int spdif_remove(struct platform_device *pdev)
 	struct resource *mem_res;
 
 	asoc_dma_platform_unregister(&pdev->dev);
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	iounmap(spdif->regs);
 
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index c724026a246f..f830c41f97dd 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -296,7 +296,6 @@ struct fsi_core {
 
 struct fsi_master {
 	void __iomem *base;
-	int irq;
 	struct fsi_priv fsia;
 	struct fsi_priv fsib;
 	const struct fsi_core *core;
@@ -1886,6 +1885,10 @@ static struct snd_soc_platform_driver fsi_soc_platform = {
 	.pcm_free	= fsi_pcm_free,
 };
 
+static const struct snd_soc_component_driver fsi_soc_component = {
+	.name		= "fsi",
+};
+
 /*
  *		platform function
  */
@@ -2002,7 +2005,6 @@ static int fsi_probe(struct platform_device *pdev)
 	}
 
 	/* master setting */
-	master->irq		= irq;
 	master->core		= core;
 	spin_lock_init(&master->lock);
 
@@ -2046,10 +2048,10 @@ static int fsi_probe(struct platform_device *pdev)
 		goto exit_fsib;
 	}
 
-	ret = snd_soc_register_dais(&pdev->dev, fsi_soc_dai,
-				    ARRAY_SIZE(fsi_soc_dai));
+	ret = snd_soc_register_component(&pdev->dev, &fsi_soc_component,
+				    fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
 	if (ret < 0) {
-		dev_err(&pdev->dev, "cannot snd dai register\n");
+		dev_err(&pdev->dev, "cannot snd component register\n");
 		goto exit_snd_soc;
 	}
 
@@ -2074,7 +2076,7 @@ static int fsi_remove(struct platform_device *pdev)
 
 	pm_runtime_disable(&pdev->dev);
 
-	snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai));
+	snd_soc_unregister_component(&pdev->dev);
 	snd_soc_unregister_platform(&pdev->dev);
 
 	fsi_stream_remove(&master->fsia);
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c
index 4cc2d64ef476..af19f77b7bf0 100644
--- a/sound/soc/sh/hac.c
+++ b/sound/soc/sh/hac.c
@@ -310,15 +310,19 @@ static struct snd_soc_dai_driver sh4_hac_dai[] = {
 #endif
 };
 
+static const struct snd_soc_component_driver sh4_hac_component = {
+	.name		= "sh4-hac",
+};
+
 static int hac_soc_platform_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_dais(&pdev->dev, sh4_hac_dai,
-			ARRAY_SIZE(sh4_hac_dai));
+	return snd_soc_register_component(&pdev->dev, &sh4_hac_component,
+					  sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
 }
 
 static int hac_soc_platform_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sh4_hac_dai));
+	snd_soc_unregister_component(&pdev->dev);
 	return 0;
 }
 
diff --git a/sound/soc/sh/migor.c b/sound/soc/sh/migor.c
index 8526e1edaf45..5014a884afee 100644
--- a/sound/soc/sh/migor.c
+++ b/sound/soc/sh/migor.c
@@ -153,7 +153,7 @@ static int migor_dai_init(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_dai_link migor_dai = {
 	.name = "wm8978",
 	.stream_name = "WM8978",
-	.cpu_dai_name = "siu-i2s-dai",
+	.cpu_dai_name = "siu-pcm-audio",
 	.codec_dai_name = "wm8978-hifi",
 	.platform_name = "siu-pcm-audio",
 	.codec_name = "wm8978.0-001a",
diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c
index 34facdc9e4ac..9dc24ffa892a 100644
--- a/sound/soc/sh/siu_dai.c
+++ b/sound/soc/sh/siu_dai.c
@@ -726,6 +726,10 @@ static struct snd_soc_dai_driver siu_i2s_dai = {
 	.ops = &siu_dai_ops,
 };
 
+static const struct snd_soc_component_driver siu_i2s_component = {
+	.name		= "siu-i2s",
+};
+
 static int siu_probe(struct platform_device *pdev)
 {
 	const struct firmware *fw_entry;
@@ -783,7 +787,8 @@ static int siu_probe(struct platform_device *pdev)
 	dev_set_drvdata(&pdev->dev, info);
 
 	/* register using ARRAY version so we can keep dai name */
-	ret = snd_soc_register_dais(&pdev->dev, &siu_i2s_dai, 1);
+	ret = snd_soc_register_component(&pdev->dev, &siu_i2s_component,
+					 &siu_i2s_dai, 1);
 	if (ret < 0)
 		goto edaiinit;
 
@@ -796,7 +801,7 @@ static int siu_probe(struct platform_device *pdev)
 	return ret;
 
 esocregp:
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 edaiinit:
 	iounmap(info->reg);
 emapreg:
@@ -823,7 +828,7 @@ static int siu_remove(struct platform_device *pdev)
 	pm_runtime_disable(&pdev->dev);
 
 	snd_soc_unregister_platform(&pdev->dev);
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	iounmap(info->reg);
 	iounmap(info->yram);
diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c
index c8e73a703934..e889405ebd38 100644
--- a/sound/soc/sh/ssi.c
+++ b/sound/soc/sh/ssi.c
@@ -379,15 +379,19 @@ static struct snd_soc_dai_driver sh4_ssi_dai[] = {
 #endif
 };
 
+static const struct snd_soc_component_driver sh4_ssi_component = {
+	.name		= "sh4-ssi",
+};
+
 static int sh4_soc_dai_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_dais(&pdev->dev, sh4_ssi_dai,
-			ARRAY_SIZE(sh4_ssi_dai));
+	return snd_soc_register_component(&pdev->dev, &sh4_ssi_component,
+					  sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai));
 }
 
 static int sh4_soc_dai_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sh4_ssi_dai));
+	snd_soc_unregister_component(&pdev->dev);
 	return 0;
 }
 
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index ed0bfb0ddb96..3853f7eb3f28 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -315,7 +315,7 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream,
 }
 
 static int soc_compr_copy(struct snd_compr_stream *cstream,
-			  const char __user *buf, size_t count)
+			  char __user *buf, size_t count)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 	struct snd_soc_platform *platform = rtd->platform;
@@ -330,11 +330,38 @@ static int soc_compr_copy(struct snd_compr_stream *cstream,
 	return ret;
 }
 
+static int sst_compr_set_metadata(struct snd_compr_stream *cstream,
+				struct snd_compr_metadata *metadata)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_platform *platform = rtd->platform;
+	int ret = 0;
+
+	if (platform->driver->compr_ops && platform->driver->compr_ops->set_metadata)
+		ret = platform->driver->compr_ops->set_metadata(cstream, metadata);
+
+	return ret;
+}
+
+static int sst_compr_get_metadata(struct snd_compr_stream *cstream,
+				struct snd_compr_metadata *metadata)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_platform *platform = rtd->platform;
+	int ret = 0;
+
+	if (platform->driver->compr_ops && platform->driver->compr_ops->get_metadata)
+		ret = platform->driver->compr_ops->get_metadata(cstream, metadata);
+
+	return ret;
+}
 /* ASoC Compress operations */
 static struct snd_compr_ops soc_compr_ops = {
 	.open		= soc_compr_open,
 	.free		= soc_compr_free,
 	.set_params	= soc_compr_set_params,
+	.set_metadata   = sst_compr_set_metadata,
+	.get_metadata	= sst_compr_get_metadata,
 	.get_params	= soc_compr_get_params,
 	.trigger	= soc_compr_trigger,
 	.pointer	= soc_compr_pointer,
@@ -357,7 +384,14 @@ int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
 	/* check client and interface hw capabilities */
 	snprintf(new_name, sizeof(new_name), "%s %s-%d",
 			rtd->dai_link->stream_name, codec_dai->name, num);
-	direction = SND_COMPRESS_PLAYBACK;
+
+	if (codec_dai->driver->playback.channels_min)
+		direction = SND_COMPRESS_PLAYBACK;
+	else if (codec_dai->driver->capture.channels_min)
+		direction = SND_COMPRESS_CAPTURE;
+	else
+		return -EINVAL;
+
 	compr = kzalloc(sizeof(*compr), GFP_KERNEL);
 	if (compr == NULL) {
 		snd_printk(KERN_ERR "Cannot allocate compr\n");
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index ff4b45a5d796..d56bbea6e75e 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -58,6 +58,7 @@ static DEFINE_MUTEX(client_mutex);
 static LIST_HEAD(dai_list);
 static LIST_HEAD(platform_list);
 static LIST_HEAD(codec_list);
+static LIST_HEAD(component_list);
 
 /*
  * This is a timeout to do a DAPM powerdown after a stream is closed().
@@ -3740,7 +3741,7 @@ static inline char *fmt_multiple_name(struct device *dev,
  *
  * @dai: DAI to register
  */
-int snd_soc_register_dai(struct device *dev,
+static int snd_soc_register_dai(struct device *dev,
 		struct snd_soc_dai_driver *dai_drv)
 {
 	struct snd_soc_codec *codec;
@@ -3787,14 +3788,13 @@ int snd_soc_register_dai(struct device *dev,
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(snd_soc_register_dai);
 
 /**
  * snd_soc_unregister_dai - Unregister a DAI from the ASoC core
  *
  * @dai: DAI to unregister
  */
-void snd_soc_unregister_dai(struct device *dev)
+static void snd_soc_unregister_dai(struct device *dev)
 {
 	struct snd_soc_dai *dai;
 
@@ -3813,7 +3813,6 @@ found:
 	kfree(dai->name);
 	kfree(dai);
 }
-EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
 
 /**
  * snd_soc_register_dais - Register multiple DAIs with the ASoC core
@@ -3821,7 +3820,7 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
  * @dai: Array of DAIs to register
  * @count: Number of DAIs
  */
-int snd_soc_register_dais(struct device *dev,
+static int snd_soc_register_dais(struct device *dev,
 		struct snd_soc_dai_driver *dai_drv, size_t count)
 {
 	struct snd_soc_codec *codec;
@@ -3885,7 +3884,6 @@ err:
 
 	return ret;
 }
-EXPORT_SYMBOL_GPL(snd_soc_register_dais);
 
 /**
  * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core
@@ -3893,31 +3891,23 @@ EXPORT_SYMBOL_GPL(snd_soc_register_dais);
  * @dai: Array of DAIs to unregister
  * @count: Number of DAIs
  */
-void snd_soc_unregister_dais(struct device *dev, size_t count)
+static void snd_soc_unregister_dais(struct device *dev, size_t count)
 {
 	int i;
 
 	for (i = 0; i < count; i++)
 		snd_soc_unregister_dai(dev);
 }
-EXPORT_SYMBOL_GPL(snd_soc_unregister_dais);
 
 /**
- * snd_soc_register_platform - Register a platform with the ASoC core
- *
- * @platform: platform to register
+ * snd_soc_add_platform - Add a platform to the ASoC core
+ * @dev: The parent device for the platform
+ * @platform: The platform to add
+ * @platform_driver: The driver for the platform
  */
-int snd_soc_register_platform(struct device *dev,
-		struct snd_soc_platform_driver *platform_drv)
+int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
+		const struct snd_soc_platform_driver *platform_drv)
 {
-	struct snd_soc_platform *platform;
-
-	dev_dbg(dev, "ASoC: platform register %s\n", dev_name(dev));
-
-	platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL);
-	if (platform == NULL)
-		return -ENOMEM;
-
 	/* create platform component name */
 	platform->name = fmt_single_name(dev, &platform->id);
 	if (platform->name == NULL) {
@@ -3940,30 +3930,76 @@ int snd_soc_register_platform(struct device *dev,
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(snd_soc_register_platform);
+EXPORT_SYMBOL_GPL(snd_soc_add_platform);
 
 /**
- * snd_soc_unregister_platform - Unregister a platform from the ASoC core
+ * snd_soc_register_platform - Register a platform with the ASoC core
  *
- * @platform: platform to unregister
+ * @platform: platform to register
  */
-void snd_soc_unregister_platform(struct device *dev)
+int snd_soc_register_platform(struct device *dev,
+		const struct snd_soc_platform_driver *platform_drv)
 {
 	struct snd_soc_platform *platform;
+	int ret;
 
-	list_for_each_entry(platform, &platform_list, list) {
-		if (dev == platform->dev)
-			goto found;
-	}
-	return;
+	dev_dbg(dev, "ASoC: platform register %s\n", dev_name(dev));
 
-found:
+	platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL);
+	if (platform == NULL)
+		return -ENOMEM;
+
+	ret = snd_soc_add_platform(dev, platform, platform_drv);
+	if (ret)
+		kfree(platform);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_register_platform);
+
+/**
+ * snd_soc_remove_platform - Remove a platform from the ASoC core
+ * @platform: the platform to remove
+ */
+void snd_soc_remove_platform(struct snd_soc_platform *platform)
+{
 	mutex_lock(&client_mutex);
 	list_del(&platform->list);
 	mutex_unlock(&client_mutex);
 
-	dev_dbg(dev, "ASoC: Unregistered platform '%s'\n", platform->name);
+	dev_dbg(platform->dev, "ASoC: Unregistered platform '%s'\n",
+		platform->name);
 	kfree(platform->name);
+}
+EXPORT_SYMBOL_GPL(snd_soc_remove_platform);
+
+struct snd_soc_platform *snd_soc_lookup_platform(struct device *dev)
+{
+	struct snd_soc_platform *platform;
+
+	list_for_each_entry(platform, &platform_list, list) {
+		if (dev == platform->dev)
+			return platform;
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_lookup_platform);
+
+/**
+ * snd_soc_unregister_platform - Unregister a platform from the ASoC core
+ *
+ * @platform: platform to unregister
+ */
+void snd_soc_unregister_platform(struct device *dev)
+{
+	struct snd_soc_platform *platform;
+
+	platform = snd_soc_lookup_platform(dev);
+	if (!platform)
+		return;
+
+	snd_soc_remove_platform(platform);
 	kfree(platform);
 }
 EXPORT_SYMBOL_GPL(snd_soc_unregister_platform);
@@ -4024,8 +4060,8 @@ int snd_soc_register_codec(struct device *dev,
 	/* create CODEC component name */
 	codec->name = fmt_single_name(dev, &codec->id);
 	if (codec->name == NULL) {
-		kfree(codec);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto fail_codec;
 	}
 
 	if (codec_drv->compress_type)
@@ -4064,7 +4100,7 @@ int snd_soc_register_codec(struct device *dev,
 						      reg_size, GFP_KERNEL);
 			if (!codec->reg_def_copy) {
 				ret = -ENOMEM;
-				goto fail;
+				goto fail_codec_name;
 			}
 		}
 	}
@@ -4088,18 +4124,22 @@ int snd_soc_register_codec(struct device *dev,
 	mutex_unlock(&client_mutex);
 
 	/* register any DAIs */
-	if (num_dai) {
-		ret = snd_soc_register_dais(dev, dai_drv, num_dai);
-		if (ret < 0)
-			dev_err(codec->dev, "ASoC: Failed to regster"
-				" DAIs: %d\n", ret);
+	ret = snd_soc_register_dais(dev, dai_drv, num_dai);
+	if (ret < 0) {
+		dev_err(codec->dev, "ASoC: Failed to regster DAIs: %d\n", ret);
+		goto fail_codec_name;
 	}
 
 	dev_dbg(codec->dev, "ASoC: Registered codec '%s'\n", codec->name);
 	return 0;
 
-fail:
+fail_codec_name:
+	mutex_lock(&client_mutex);
+	list_del(&codec->list);
+	mutex_unlock(&client_mutex);
+
 	kfree(codec->name);
+fail_codec:
 	kfree(codec);
 	return ret;
 }
@@ -4113,7 +4153,6 @@ EXPORT_SYMBOL_GPL(snd_soc_register_codec);
 void snd_soc_unregister_codec(struct device *dev)
 {
 	struct snd_soc_codec *codec;
-	int i;
 
 	list_for_each_entry(codec, &codec_list, list) {
 		if (dev == codec->dev)
@@ -4122,9 +4161,7 @@ void snd_soc_unregister_codec(struct device *dev)
 	return;
 
 found:
-	if (codec->num_dai)
-		for (i = 0; i < codec->num_dai; i++)
-			snd_soc_unregister_dai(dev);
+	snd_soc_unregister_dais(dev, codec->num_dai);
 
 	mutex_lock(&client_mutex);
 	list_del(&codec->list);
@@ -4139,6 +4176,92 @@ found:
 }
 EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
 
+
+/**
+ * snd_soc_register_component - Register a component with the ASoC core
+ *
+ */
+int snd_soc_register_component(struct device *dev,
+			 const struct snd_soc_component_driver *cmpnt_drv,
+			 struct snd_soc_dai_driver *dai_drv,
+			 int num_dai)
+{
+	struct snd_soc_component *cmpnt;
+	int ret;
+
+	dev_dbg(dev, "component register %s\n", dev_name(dev));
+
+	cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL);
+	if (!cmpnt) {
+		dev_err(dev, "ASoC: Failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	cmpnt->name = fmt_single_name(dev, &cmpnt->id);
+	if (!cmpnt->name) {
+		dev_err(dev, "ASoC: Failed to simplifying name\n");
+		return -ENOMEM;
+	}
+
+	cmpnt->dev	= dev;
+	cmpnt->driver	= cmpnt_drv;
+	cmpnt->num_dai	= num_dai;
+
+	/*
+	 * snd_soc_register_dai()  uses fmt_single_name(), and
+	 * snd_soc_register_dais() uses fmt_multiple_name()
+	 * for dai->name which is used for name based matching
+	 */
+	if (1 == num_dai)
+		ret = snd_soc_register_dai(dev, dai_drv);
+	else
+		ret = snd_soc_register_dais(dev, dai_drv, num_dai);
+	if (ret < 0) {
+		dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret);
+		goto error_component_name;
+	}
+
+	mutex_lock(&client_mutex);
+	list_add(&cmpnt->list, &component_list);
+	mutex_unlock(&client_mutex);
+
+	dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name);
+
+	return ret;
+
+error_component_name:
+	kfree(cmpnt->name);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_register_component);
+
+/**
+ * snd_soc_unregister_component - Unregister a component from the ASoC core
+ *
+ */
+void snd_soc_unregister_component(struct device *dev)
+{
+	struct snd_soc_component *cmpnt;
+
+	list_for_each_entry(cmpnt, &component_list, list) {
+		if (dev == cmpnt->dev)
+			goto found;
+	}
+	return;
+
+found:
+	snd_soc_unregister_dais(dev, cmpnt->num_dai);
+
+	mutex_lock(&client_mutex);
+	list_del(&cmpnt->list);
+	mutex_unlock(&client_mutex);
+
+	dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name);
+	kfree(cmpnt->name);
+}
+EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
+
 /* Retrieve a card's name from device tree */
 int snd_soc_of_parse_card_name(struct snd_soc_card *card,
 			       const char *propname)
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index d6d9ba2e6916..21779a6a781a 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -504,17 +504,27 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
 	return 0;
 }
 
-/* create new dapm mixer control */
-static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
+/*
+ * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
+ * create it. Either way, add the widget into the control's widget list
+ */
+static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
+	int kci, struct snd_soc_dapm_path *path)
 {
 	struct snd_soc_dapm_context *dapm = w->dapm;
-	int i, ret = 0;
-	size_t name_len, prefix_len;
-	struct snd_soc_dapm_path *path;
 	struct snd_card *card = dapm->card->snd_card;
 	const char *prefix;
+	size_t prefix_len;
+	int shared;
+	struct snd_kcontrol *kcontrol;
 	struct snd_soc_dapm_widget_list *wlist;
+	int wlistentries;
 	size_t wlistsize;
+	bool wname_in_long_name, kcname_in_long_name;
+	size_t name_len;
+	char *long_name;
+	const char *name;
+	int ret;
 
 	if (dapm->codec)
 		prefix = dapm->codec->name_prefix;
@@ -526,103 +536,141 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
 	else
 		prefix_len = 0;
 
-	/* add kcontrol */
-	for (i = 0; i < w->num_kcontrols; i++) {
+	shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
+					 &kcontrol);
 
-		/* match name */
-		list_for_each_entry(path, &w->sources, list_sink) {
+	if (kcontrol) {
+		wlist = kcontrol->private_data;
+		wlistentries = wlist->num_widgets + 1;
+	} else {
+		wlist = NULL;
+		wlistentries = 1;
+	}
 
-			/* mixer/mux paths name must match control name */
-			if (path->name != (char *)w->kcontrol_news[i].name)
-				continue;
+	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 (w->kcontrols[i]) {
-				path->kcontrol = w->kcontrols[i];
-				continue;
+	if (!kcontrol) {
+		if (shared) {
+			wname_in_long_name = false;
+			kcname_in_long_name = true;
+		} else {
+			switch (w->id) {
+			case snd_soc_dapm_switch:
+			case snd_soc_dapm_mixer:
+				wname_in_long_name = true;
+				kcname_in_long_name = true;
+				break;
+			case snd_soc_dapm_mixer_named_ctl:
+				wname_in_long_name = false;
+				kcname_in_long_name = true;
+				break;
+			case snd_soc_dapm_mux:
+			case snd_soc_dapm_virt_mux:
+			case snd_soc_dapm_value_mux:
+				wname_in_long_name = true;
+				kcname_in_long_name = false;
+				break;
+			default:
+				kfree(wlist);
+				return -EINVAL;
 			}
+		}
+
+		if (wname_in_long_name && kcname_in_long_name) {
+			name_len = strlen(w->name) - prefix_len + 1 +
+				   strlen(w->kcontrol_news[kci].name) + 1;
 
-			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);
+			long_name = kmalloc(name_len, GFP_KERNEL);
+			if (long_name == NULL) {
+				kfree(wlist);
 				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.
+
+			/*
+			 * 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.
 			 */
-			name_len = strlen(w->kcontrol_news[i].name) + 1;
-			if (w->id != snd_soc_dapm_mixer_named_ctl)
-				name_len += 1 + strlen(w->name);
+			snprintf(long_name, name_len, "%s %s",
+				 w->name + prefix_len,
+				 w->kcontrol_news[kci].name);
+			long_name[name_len - 1] = '\0';
+
+			name = long_name;
+		} else if (wname_in_long_name) {
+			long_name = NULL;
+			name = w->name + prefix_len;
+		} else {
+			long_name = NULL;
+			name = w->kcontrol_news[kci].name;
+		}
 
-			path->long_name = kmalloc(name_len, GFP_KERNEL);
+		kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name,
+					prefix);
+		ret = snd_ctl_add(card, kcontrol);
+		if (ret < 0) {
+			dev_err(dapm->dev,
+				"ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
+				w->name, name, ret);
+			kfree(wlist);
+			kfree(long_name);
+			return ret;
+		}
 
-			if (path->long_name == NULL) {
-				kfree(wlist);
-				return -ENOMEM;
-			}
+		path->long_name = long_name;
+	}
 
-			switch (w->id) {
-			default:
-				/* 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.
-				 */
-				snprintf((char *)path->long_name, name_len,
-					 "%s %s", w->name + prefix_len,
-					 w->kcontrol_news[i].name);
-				break;
-			case snd_soc_dapm_mixer_named_ctl:
-				snprintf((char *)path->long_name, name_len,
-					 "%s", w->kcontrol_news[i].name);
-				break;
-			}
+	kcontrol->private_data = wlist;
+	w->kcontrols[kci] = kcontrol;
+	path->kcontrol = kcontrol;
 
-			((char *)path->long_name)[name_len - 1] = '\0';
+	return 0;
+}
 
-			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 widget"
-					" %s dapm kcontrol %s: %d\n",
-					w->name, path->long_name, ret);
-				kfree(wlist);
-				kfree(path->long_name);
-				path->long_name = NULL;
-				return ret;
+/* create new dapm mixer control */
+static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
+{
+	int i, ret;
+	struct snd_soc_dapm_path *path;
+
+	/* add kcontrol */
+	for (i = 0; i < w->num_kcontrols; i++) {
+		/* match name */
+		list_for_each_entry(path, &w->sources, list_sink) {
+			/* mixer/mux paths name must match control name */
+			if (path->name != (char *)w->kcontrol_news[i].name)
+				continue;
+
+			if (w->kcontrols[i]) {
+				path->kcontrol = w->kcontrols[i];
+				continue;
 			}
-			w->kcontrols[i] = path->kcontrol;
+
+			ret = dapm_create_or_share_mixmux_kcontrol(w, i, path);
+			if (ret < 0)
+				return ret;
 		}
 	}
-	return ret;
+
+	return 0;
 }
 
 /* create new dapm mux control */
 static int dapm_new_mux(struct snd_soc_dapm_widget *w)
 {
 	struct snd_soc_dapm_context *dapm = w->dapm;
-	struct snd_soc_dapm_path *path = NULL;
-	struct snd_kcontrol *kcontrol;
-	struct snd_card *card = dapm->card->snd_card;
-	const char *prefix;
-	size_t prefix_len;
+	struct snd_soc_dapm_path *path;
 	int ret;
-	struct snd_soc_dapm_widget_list *wlist;
-	int shared, wlistentries;
-	size_t wlistsize;
-	const char *name;
 
 	if (w->num_kcontrols != 1) {
 		dev_err(dapm->dev,
@@ -631,65 +679,19 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
 		return -EINVAL;
 	}
 
-	shared = dapm_is_shared_kcontrol(dapm, w, &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 (!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->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: %d\n",
-				w->name, ret);
-			kfree(wlist);
-			return ret;
-		}
+	path = list_first_entry(&w->sources, struct snd_soc_dapm_path,
+				list_sink);
+	if (!path) {
+		dev_err(dapm->dev, "ASoC: mux %s has no paths\n", w->name);
+		return -EINVAL;
 	}
 
-	kcontrol->private_data = wlist;
-
-	w->kcontrols[0] = kcontrol;
+	ret = dapm_create_or_share_mixmux_kcontrol(w, 0, path);
+	if (ret < 0)
+		return ret;
 
 	list_for_each_entry(path, &w->sources, list_sink)
-		path->kcontrol = kcontrol;
+		path->kcontrol = w->kcontrols[0];
 
 	return 0;
 }
@@ -705,14 +707,33 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w)
 }
 
 /* reset 'walked' bit for each dapm path */
-static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm)
+static void dapm_clear_walk_output(struct snd_soc_dapm_context *dapm,
+				   struct list_head *sink)
 {
 	struct snd_soc_dapm_path *p;
 
-	list_for_each_entry(p, &dapm->card->paths, list)
-		p->walked = 0;
+	list_for_each_entry(p, sink, list_source) {
+		if (p->walked) {
+			p->walked = 0;
+			dapm_clear_walk_output(dapm, &p->sink->sinks);
+		}
+	}
 }
 
+static void dapm_clear_walk_input(struct snd_soc_dapm_context *dapm,
+				  struct list_head *source)
+{
+	struct snd_soc_dapm_path *p;
+
+	list_for_each_entry(p, source, list_sink) {
+		if (p->walked) {
+			p->walked = 0;
+			dapm_clear_walk_input(dapm, &p->source->sources);
+		}
+	}
+}
+
+
 /* We implement power down on suspend by checking the power state of
  * the ALSA card - when we are suspending the ALSA state for the card
  * is set to D3.
@@ -995,13 +1016,17 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
 	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 	dapm_reset(card);
 
-	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		paths = is_connected_output_ep(dai->playback_widget, list);
-	else
+		dapm_clear_walk_output(&card->dapm,
+				       &dai->playback_widget->sinks);
+	} else {
 		paths = is_connected_input_ep(dai->capture_widget, list);
+		dapm_clear_walk_input(&card->dapm,
+				      &dai->capture_widget->sources);
+	}
 
 	trace_snd_soc_dapm_connected(paths, stream);
-	dapm_clear_walk(&card->dapm);
 	mutex_unlock(&card->dapm_mutex);
 
 	return paths;
@@ -1104,9 +1129,9 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
 	DAPM_UPDATE_STAT(w, power_checks);
 
 	in = is_connected_input_ep(w, NULL);
-	dapm_clear_walk(w->dapm);
+	dapm_clear_walk_input(w->dapm, &w->sources);
 	out = is_connected_output_ep(w, NULL);
-	dapm_clear_walk(w->dapm);
+	dapm_clear_walk_output(w->dapm, &w->sinks);
 	return out != 0 && in != 0;
 }
 
@@ -1129,7 +1154,7 @@ static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
 
 	if (w->active) {
 		in = is_connected_input_ep(w, NULL);
-		dapm_clear_walk(w->dapm);
+		dapm_clear_walk_input(w->dapm, &w->sources);
 		return in != 0;
 	} else {
 		return dapm_generic_check_power(w);
@@ -1145,7 +1170,7 @@ static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
 
 	if (w->active) {
 		out = is_connected_output_ep(w, NULL);
-		dapm_clear_walk(w->dapm);
+		dapm_clear_walk_output(w->dapm, &w->sinks);
 		return out != 0;
 	} else {
 		return dapm_generic_check_power(w);
@@ -1177,8 +1202,6 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
 			return 1;
 	}
 
-	dapm_clear_walk(w->dapm);
-
 	return 0;
 }
 
@@ -1759,9 +1782,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
 		return -ENOMEM;
 
 	in = is_connected_input_ep(w, NULL);
-	dapm_clear_walk(w->dapm);
+	dapm_clear_walk_input(w->dapm, &w->sources);
 	out = is_connected_output_ep(w, NULL);
-	dapm_clear_walk(w->dapm);
+	dapm_clear_walk_output(w->dapm, &w->sinks);
 
 	ret = snprintf(buf, PAGE_SIZE, "%s: %s%s  in %d out %d",
 		       w->name, w->power ? "On" : "Off",
@@ -3137,7 +3160,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
 		break;
 	}
 
-	dapm->n_widgets++;
 	w->dapm = dapm;
 	w->codec = dapm->codec;
 	w->platform = dapm->platform;
diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c
index 111b7d921e89..aa924d9b7986 100644
--- a/sound/soc/soc-dmaengine-pcm.c
+++ b/sound/soc/soc-dmaengine-pcm.c
@@ -33,8 +33,6 @@ struct dmaengine_pcm_runtime_data {
 	dma_cookie_t cookie;
 
 	unsigned int pos;
-
-	void *data;
 };
 
 static inline struct dmaengine_pcm_runtime_data *substream_to_prtd(
@@ -43,33 +41,6 @@ static inline struct dmaengine_pcm_runtime_data *substream_to_prtd(
 	return substream->runtime->private_data;
 }
 
-/**
- * snd_dmaengine_pcm_set_data - Set dmaengine substream private data
- * @substream: PCM substream
- * @data: Data to set
- */
-void snd_dmaengine_pcm_set_data(struct snd_pcm_substream *substream, void *data)
-{
-	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
-
-	prtd->data = data;
-}
-EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_data);
-
-/**
- * snd_dmaengine_pcm_get_data - Get dmaeinge substream private data
- * @substream: PCM substream
- *
- * Returns the data previously set with snd_dmaengine_pcm_set_data
- */
-void *snd_dmaengine_pcm_get_data(struct snd_pcm_substream *substream)
-{
-	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
-
-	return prtd->data;
-}
-EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_get_data);
-
 struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream)
 {
 	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
@@ -118,10 +89,49 @@ int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream,
 		slave_config->src_addr_width = buswidth;
 	}
 
+	slave_config->device_fc = false;
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_hwparams_to_dma_slave_config);
 
+/**
+ * snd_dmaengine_pcm_set_config_from_dai_data() - Initializes a dma slave config
+ *  using DAI DMA data.
+ * @substream: PCM substream
+ * @dma_data: DAI DMA data
+ * @slave_config: DMA slave configuration
+ *
+ * Initializes the {dst,src}_addr, {dst,src}_maxburst, {dst,src}_addr_width and
+ * slave_id fields of the DMA slave config from the same fields of the DAI DMA
+ * data struct. The src and dst fields will be initialized depending on the
+ * direction of the substream. If the substream is a playback stream the dst
+ * fields will be initialized, if it is a capture stream the src fields will be
+ * initialized. The {dst,src}_addr_width field will only be initialized if the
+ * addr_width field of the DAI DMA data struct is not equal to
+ * DMA_SLAVE_BUSWIDTH_UNDEFINED.
+ */
+void snd_dmaengine_pcm_set_config_from_dai_data(
+	const struct snd_pcm_substream *substream,
+	const struct snd_dmaengine_dai_dma_data *dma_data,
+	struct dma_slave_config *slave_config)
+{
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		slave_config->dst_addr = dma_data->addr;
+		slave_config->dst_maxburst = dma_data->maxburst;
+		if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED)
+			slave_config->dst_addr_width = dma_data->addr_width;
+	} else {
+		slave_config->src_addr = dma_data->addr;
+		slave_config->src_maxburst = dma_data->maxburst;
+		if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED)
+			slave_config->src_addr_width = dma_data->addr_width;
+	}
+
+	slave_config->slave_id = dma_data->slave_id;
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_config_from_dai_data);
+
 static void dmaengine_pcm_dma_complete(void *arg)
 {
 	struct snd_pcm_substream *substream = arg;
@@ -244,44 +254,48 @@ snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream)
 }
 EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer);
 
-static int dmaengine_pcm_request_channel(struct dmaengine_pcm_runtime_data *prtd,
-	dma_filter_fn filter_fn, void *filter_data)
+/**
+ * snd_dmaengine_pcm_request_channel - Request channel for the dmaengine PCM
+ * @filter_fn: Filter function used to request the DMA channel
+ * @filter_data: Data passed to the DMA filter function
+ *
+ * Returns NULL or the requested DMA channel.
+ *
+ * This function request a DMA channel for usage with dmaengine PCM.
+ */
+struct dma_chan *snd_dmaengine_pcm_request_channel(dma_filter_fn filter_fn,
+	void *filter_data)
 {
 	dma_cap_mask_t mask;
 
 	dma_cap_zero(mask);
 	dma_cap_set(DMA_SLAVE, mask);
 	dma_cap_set(DMA_CYCLIC, mask);
-	prtd->dma_chan = dma_request_channel(mask, filter_fn, filter_data);
 
-	if (!prtd->dma_chan)
-		return -ENXIO;
-
-	return 0;
+	return dma_request_channel(mask, filter_fn, filter_data);
 }
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_request_channel);
 
 /**
  * snd_dmaengine_pcm_open - Open a dmaengine based PCM substream
  * @substream: PCM substream
- * @filter_fn: Filter function used to request the DMA channel
- * @filter_data: Data passed to the DMA filter function
+ * @chan: DMA channel to use for data transfers
  *
  * Returns 0 on success, a negative error code otherwise.
  *
- * This function will request a DMA channel using the passed filter function and
- * data. The function should usually be called from the pcm open callback.
- *
- * Note that this function will use private_data field of the substream's
- * runtime. So it is not availabe to your pcm driver implementation. If you need
- * to keep additional data attached to a substream use
- * snd_dmaengine_pcm_{set,get}_data.
+ * The function should usually be called from the pcm open callback. Note that
+ * this function will use private_data field of the substream's runtime. So it
+ * is not availabe to your pcm driver implementation.
  */
 int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
-	dma_filter_fn filter_fn, void *filter_data)
+	struct dma_chan *chan)
 {
 	struct dmaengine_pcm_runtime_data *prtd;
 	int ret;
 
+	if (!chan)
+		return -ENXIO;
+
 	ret = snd_pcm_hw_constraint_integer(substream->runtime,
 					    SNDRV_PCM_HW_PARAM_PERIODS);
 	if (ret < 0)
@@ -291,11 +305,7 @@ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
 	if (!prtd)
 		return -ENOMEM;
 
-	ret = dmaengine_pcm_request_channel(prtd, filter_fn, filter_data);
-	if (ret < 0) {
-		kfree(prtd);
-		return ret;
-	}
+	prtd->dma_chan = chan;
 
 	substream->runtime->private_data = prtd;
 
@@ -304,6 +314,27 @@ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
 EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open);
 
 /**
+ * snd_dmaengine_pcm_open_request_chan - Open a dmaengine based PCM substream and request channel
+ * @substream: PCM substream
+ * @filter_fn: Filter function used to request the DMA channel
+ * @filter_data: Data passed to the DMA filter function
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ *
+ * This function will request a DMA channel using the passed filter function and
+ * data. The function should usually be called from the pcm open callback. Note
+ * that this function will use private_data field of the substream's runtime. So
+ * it is not availabe to your pcm driver implementation.
+ */
+int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream,
+	dma_filter_fn filter_fn, void *filter_data)
+{
+	return snd_dmaengine_pcm_open(substream,
+		    snd_dmaengine_pcm_request_channel(filter_fn, filter_data));
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan);
+
+/**
  * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream
  * @substream: PCM substream
  */
@@ -311,11 +342,26 @@ int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream)
 {
 	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
 
-	dma_release_channel(prtd->dma_chan);
 	kfree(prtd);
 
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close);
 
+/**
+ * snd_dmaengine_pcm_release_chan_close - Close a dmaengine based PCM substream and release channel
+ * @substream: PCM substream
+ *
+ * Releases the DMA channel associated with the PCM substream.
+ */
+int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream)
+{
+	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+
+	dma_release_channel(prtd->dma_chan);
+
+	return snd_dmaengine_pcm_close(substream);
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan);
+
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
new file mode 100644
index 000000000000..e29ec3cd84b1
--- /dev/null
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -0,0 +1,300 @@
+/*
+ *  Copyright (C) 2013, Analog Devices Inc.
+ *	Author: Lars-Peter Clausen <lars@metafoo.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.
+ *
+ *  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.
+ *
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/dmaengine.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+
+#include <sound/dmaengine_pcm.h>
+
+struct dmaengine_pcm {
+	struct dma_chan *chan[SNDRV_PCM_STREAM_CAPTURE + 1];
+	const struct snd_dmaengine_pcm_config *config;
+	struct snd_soc_platform platform;
+	unsigned int flags;
+};
+
+static struct dmaengine_pcm *soc_platform_to_pcm(struct snd_soc_platform *p)
+{
+	return container_of(p, struct dmaengine_pcm, platform);
+}
+
+/**
+ * snd_dmaengine_pcm_prepare_slave_config() - Generic prepare_slave_config callback
+ * @substream: PCM substream
+ * @params: hw_params
+ * @slave_config: DMA slave config to prepare
+ *
+ * This function can be used as a generic prepare_slave_config callback for
+ * platforms which make use of the snd_dmaengine_dai_dma_data struct for their
+ * DAI DMA data. Internally the function will first call
+ * snd_hwparams_to_dma_slave_config to fill in the slave config based on the
+ * hw_params, followed by snd_dmaengine_set_config_from_dai_data to fill in the
+ * remaining fields based on the DAI DMA data.
+ */
+int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_dmaengine_dai_dma_data *dma_data;
+	int ret;
+
+	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+	ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config);
+	if (ret)
+		return ret;
+
+	snd_dmaengine_pcm_set_config_from_dai_data(substream, dma_data,
+		slave_config);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_prepare_slave_config);
+
+static int dmaengine_pcm_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
+	struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
+	struct dma_slave_config slave_config;
+	int ret;
+
+	if (pcm->config->prepare_slave_config) {
+		ret = pcm->config->prepare_slave_config(substream, params,
+				&slave_config);
+		if (ret)
+			return ret;
+
+		ret = dmaengine_slave_config(chan, &slave_config);
+		if (ret)
+			return ret;
+	}
+
+	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+}
+
+static int dmaengine_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
+	struct dma_chan *chan = pcm->chan[substream->stream];
+	int ret;
+
+	ret = snd_soc_set_runtime_hwparams(substream,
+				pcm->config->pcm_hardware);
+	if (ret)
+		return ret;
+
+	return snd_dmaengine_pcm_open(substream, chan);
+}
+
+static struct device *dmaengine_dma_dev(struct dmaengine_pcm *pcm,
+	struct snd_pcm_substream *substream)
+{
+	if (!pcm->chan[substream->stream])
+		return NULL;
+
+	return pcm->chan[substream->stream]->device->dev;
+}
+
+static void dmaengine_pcm_free(struct snd_pcm *pcm)
+{
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static struct dma_chan *dmaengine_pcm_compat_request_channel(
+	struct snd_soc_pcm_runtime *rtd,
+	struct snd_pcm_substream *substream)
+{
+	struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
+
+	if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) && pcm->chan[0])
+		return pcm->chan[0];
+
+	if (pcm->config->compat_request_channel)
+		return pcm->config->compat_request_channel(rtd, substream);
+
+	return snd_dmaengine_pcm_request_channel(pcm->config->compat_filter_fn,
+		snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
+}
+
+static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
+	const struct snd_dmaengine_pcm_config *config = pcm->config;
+	struct snd_pcm_substream *substream;
+	unsigned int i;
+	int ret;
+
+	for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) {
+		substream = rtd->pcm->streams[i].substream;
+		if (!substream)
+			continue;
+
+		if (!pcm->chan[i] && (pcm->flags & SND_DMAENGINE_PCM_FLAG_COMPAT)) {
+			pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd,
+				substream);
+		}
+
+		if (!pcm->chan[i]) {
+			dev_err(rtd->platform->dev,
+				"Missing dma channel for stream: %d\n", i);
+			ret = -EINVAL;
+			goto err_free;
+		}
+
+		ret = snd_pcm_lib_preallocate_pages(substream,
+				SNDRV_DMA_TYPE_DEV,
+				dmaengine_dma_dev(pcm, substream),
+				config->prealloc_buffer_size,
+				config->pcm_hardware->buffer_bytes_max);
+		if (ret)
+			goto err_free;
+	}
+
+	return 0;
+
+err_free:
+	dmaengine_pcm_free(rtd->pcm);
+	return ret;
+}
+
+static const struct snd_pcm_ops dmaengine_pcm_ops = {
+	.open		= dmaengine_pcm_open,
+	.close		= snd_dmaengine_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= dmaengine_pcm_hw_params,
+	.hw_free	= snd_pcm_lib_free_pages,
+	.trigger	= snd_dmaengine_pcm_trigger,
+	.pointer	= snd_dmaengine_pcm_pointer,
+};
+
+static const struct snd_soc_platform_driver dmaengine_pcm_platform = {
+	.ops		= &dmaengine_pcm_ops,
+	.pcm_new	= dmaengine_pcm_new,
+	.pcm_free	= dmaengine_pcm_free,
+	.probe_order	= SND_SOC_COMP_ORDER_LATE,
+};
+
+static const struct snd_pcm_ops dmaengine_no_residue_pcm_ops = {
+	.open		= dmaengine_pcm_open,
+	.close		= snd_dmaengine_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= dmaengine_pcm_hw_params,
+	.hw_free	= snd_pcm_lib_free_pages,
+	.trigger	= snd_dmaengine_pcm_trigger,
+	.pointer	= snd_dmaengine_pcm_pointer_no_residue,
+};
+
+static const struct snd_soc_platform_driver dmaengine_no_residue_pcm_platform = {
+	.ops		= &dmaengine_no_residue_pcm_ops,
+	.pcm_new	= dmaengine_pcm_new,
+	.pcm_free	= dmaengine_pcm_free,
+	.probe_order	= SND_SOC_COMP_ORDER_LATE,
+};
+
+static const char * const dmaengine_pcm_dma_channel_names[] = {
+	[SNDRV_PCM_STREAM_PLAYBACK] = "tx",
+	[SNDRV_PCM_STREAM_CAPTURE] = "rx",
+};
+
+static void dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm,
+	struct device *dev)
+{
+	unsigned int i;
+
+	if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_DT) || !dev->of_node)
+		return;
+
+	if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) {
+		pcm->chan[0] = dma_request_slave_channel(dev, "rx-tx");
+		pcm->chan[1] = pcm->chan[0];
+	} else {
+		for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) {
+			pcm->chan[i] = dma_request_slave_channel(dev,
+					dmaengine_pcm_dma_channel_names[i]);
+		}
+	}
+}
+
+/**
+ * snd_dmaengine_pcm_register - Register a dmaengine based PCM device
+ * @dev: The parent device for the PCM device
+ * @config: Platform specific PCM configuration
+ * @flags: Platform specific quirks
+ */
+int snd_dmaengine_pcm_register(struct device *dev,
+	const struct snd_dmaengine_pcm_config *config, unsigned int flags)
+{
+	struct dmaengine_pcm *pcm;
+
+	pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
+	if (!pcm)
+		return -ENOMEM;
+
+	pcm->config = config;
+	pcm->flags = flags;
+
+	dmaengine_pcm_request_chan_of(pcm, dev);
+
+	if (flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE)
+		return snd_soc_add_platform(dev, &pcm->platform,
+				&dmaengine_no_residue_pcm_platform);
+	else
+		return snd_soc_add_platform(dev, &pcm->platform,
+				&dmaengine_pcm_platform);
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_register);
+
+/**
+ * snd_dmaengine_pcm_unregister - Removes a dmaengine based PCM device
+ * @dev: Parent device the PCM was register with
+ *
+ * Removes a dmaengine based PCM device previously registered with
+ * snd_dmaengine_pcm_register.
+ */
+void snd_dmaengine_pcm_unregister(struct device *dev)
+{
+	struct snd_soc_platform *platform;
+	struct dmaengine_pcm *pcm;
+	unsigned int i;
+
+	platform = snd_soc_lookup_platform(dev);
+	if (!platform)
+		return;
+
+	pcm = soc_platform_to_pcm(platform);
+
+	for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) {
+		if (pcm->chan[i]) {
+			dma_release_channel(pcm->chan[i]);
+			if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX)
+				break;
+		}
+	}
+
+	snd_soc_remove_platform(platform);
+	kfree(pcm);
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_unregister);
+
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c
index 29183ef2b93d..8ca9ecc5ac57 100644
--- a/sound/soc/soc-io.c
+++ b/sound/soc/soc-io.c
@@ -158,10 +158,7 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
 		return -EINVAL;
 	}
 
-	if (IS_ERR(codec->control_data))
-		return PTR_ERR(codec->control_data);
-
-	return 0;
+	return PTR_RET(codec->control_data);
 }
 EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
 #else
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c
index fe4541df498c..4b3be6c3c91e 100644
--- a/sound/soc/soc-utils.c
+++ b/sound/soc/soc-utils.c
@@ -90,8 +90,33 @@ static struct snd_soc_platform_driver dummy_platform = {
 };
 
 static struct snd_soc_codec_driver dummy_codec;
+
+#define STUB_RATES	SNDRV_PCM_RATE_8000_192000
+#define STUB_FORMATS	(SNDRV_PCM_FMTBIT_S8 | \
+			SNDRV_PCM_FMTBIT_U8 | \
+			SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_U16_LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | \
+			SNDRV_PCM_FMTBIT_U24_LE | \
+			SNDRV_PCM_FMTBIT_S32_LE | \
+			SNDRV_PCM_FMTBIT_U32_LE | \
+			SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
 static struct snd_soc_dai_driver dummy_dai = {
 	.name = "snd-soc-dummy-dai",
+	.playback = {
+		.stream_name	= "Playback",
+		.channels_min	= 1,
+		.channels_max	= 384,
+		.rates		= STUB_RATES,
+		.formats	= STUB_FORMATS,
+	},
+	.capture = {
+		.stream_name	= "Capture",
+		.channels_min	= 1,
+		.channels_max	= 384,
+		.rates = STUB_RATES,
+		.formats = STUB_FORMATS,
+	 },
 };
 
 static int snd_soc_dummy_probe(struct platform_device *pdev)
diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c
index c7c4b20395bb..14d57e89bcba 100644
--- a/sound/soc/spear/spdif_in.c
+++ b/sound/soc/spear/spdif_in.c
@@ -170,6 +170,10 @@ struct snd_soc_dai_driver spdif_in_dai = {
 	.ops = &spdif_in_dai_ops,
 };
 
+static const struct snd_soc_component_driver spdif_in_component = {
+	.name		= "spdif-in",
+};
+
 static irqreturn_t spdif_in_irq(int irq, void *arg)
 {
 	struct spdif_in_dev *host = (struct spdif_in_dev *)arg;
@@ -258,7 +262,8 @@ static int spdif_in_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	ret = snd_soc_register_dai(&pdev->dev, &spdif_in_dai);
+	ret = snd_soc_register_component(&pdev->dev, &spdif_in_component,
+					 &spdif_in_dai, 1);
 	if (ret != 0) {
 		clk_put(host->clk);
 		return ret;
@@ -271,7 +276,7 @@ static int spdif_in_remove(struct platform_device *pdev)
 {
 	struct spdif_in_dev *host = dev_get_drvdata(&pdev->dev);
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	dev_set_drvdata(&pdev->dev, NULL);
 
 	clk_put(host->clk);
diff --git a/sound/soc/spear/spdif_out.c b/sound/soc/spear/spdif_out.c
index 5eac4cda2fd7..1e3c3dda3598 100644
--- a/sound/soc/spear/spdif_out.c
+++ b/sound/soc/spear/spdif_out.c
@@ -270,6 +270,10 @@ static struct snd_soc_dai_driver spdif_out_dai = {
 	.ops = &spdif_out_dai_ops,
 };
 
+static const struct snd_soc_component_driver spdif_out_component = {
+	.name		= "spdif-out",
+};
+
 static int spdif_out_probe(struct platform_device *pdev)
 {
 	struct spdif_out_dev *host;
@@ -314,7 +318,8 @@ static int spdif_out_probe(struct platform_device *pdev)
 
 	dev_set_drvdata(&pdev->dev, host);
 
-	ret = snd_soc_register_dai(&pdev->dev, &spdif_out_dai);
+	ret = snd_soc_register_component(&pdev->dev, &spdif_out_component,
+					 &spdif_out_dai, 1);
 	if (ret != 0) {
 		clk_put(host->clk);
 		return ret;
@@ -327,7 +332,7 @@ static int spdif_out_remove(struct platform_device *pdev)
 {
 	struct spdif_out_dev *host = dev_get_drvdata(&pdev->dev);
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	dev_set_drvdata(&pdev->dev, NULL);
 
 	clk_put(host->clk);
diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c
index 5e7aebe1e664..2fbd4899d8ef 100644
--- a/sound/soc/spear/spear_pcm.c
+++ b/sound/soc/spear/spear_pcm.c
@@ -25,7 +25,7 @@
 #include <sound/soc.h>
 #include <sound/spear_dma.h>
 
-struct snd_pcm_hardware spear_pcm_hardware = {
+static struct snd_pcm_hardware spear_pcm_hardware = {
 	.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
 		 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
 		 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
@@ -64,21 +64,8 @@ static int spear_pcm_open(struct snd_pcm_substream *substream)
 	if (ret)
 		return ret;
 
-	ret = snd_dmaengine_pcm_open(substream, dma_data->filter, dma_data);
-	if (ret)
-		return ret;
-
-	snd_dmaengine_pcm_set_data(substream, dma_data);
-
-	return 0;
-}
-
-static int spear_pcm_close(struct snd_pcm_substream *substream)
-{
-
-	snd_dmaengine_pcm_close(substream);
-
-	return 0;
+	return snd_dmaengine_pcm_open_request_chan(substream, dma_data->filter,
+				dma_data);
 }
 
 static int spear_pcm_mmap(struct snd_pcm_substream *substream,
@@ -93,7 +80,7 @@ static int spear_pcm_mmap(struct snd_pcm_substream *substream,
 
 static struct snd_pcm_ops spear_pcm_ops = {
 	.open		= spear_pcm_open,
-	.close		= spear_pcm_close,
+	.close		= snd_dmaengine_pcm_close_release_chan,
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= spear_pcm_hw_params,
 	.hw_free	= spear_pcm_hw_free,
@@ -178,7 +165,7 @@ static int spear_pcm_new(struct snd_soc_pcm_runtime *rtd)
 	return 0;
 }
 
-struct snd_soc_platform_driver spear_soc_platform = {
+static struct snd_soc_platform_driver spear_soc_platform = {
 	.ops		=	&spear_pcm_ops,
 	.pcm_new	=	spear_pcm_new,
 	.pcm_free	=	spear_pcm_free,
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index dbc27ce1d4de..b1c9d573da05 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -2,7 +2,7 @@ config SND_SOC_TEGRA
 	tristate "SoC Audio for the Tegra System-on-Chip"
 	depends on ARCH_TEGRA && TEGRA20_APB_DMA
 	select REGMAP_MMIO
-	select SND_SOC_DMAENGINE_PCM if TEGRA20_APB_DMA
+	select SND_SOC_GENERIC_DMAENGINE_PCM if TEGRA20_APB_DMA
 	help
 	  Say Y or M here if you want support for SoC audio on Tegra.
 
diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c
index 336dcdd3e8a4..2f70ea7f6618 100644
--- a/sound/soc/tegra/tegra20_ac97.c
+++ b/sound/soc/tegra/tegra20_ac97.c
@@ -35,6 +35,7 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
 #include "tegra_asoc_utils.h"
 #include "tegra20_ac97.h"
@@ -248,6 +249,10 @@ static struct snd_soc_dai_driver tegra20_ac97_dai = {
 	.ops = &tegra20_ac97_dai_ops,
 };
 
+static const struct snd_soc_component_driver tegra20_ac97_component = {
+	.name		= DRV_NAME,
+};
+
 static bool tegra20_ac97_wr_rd_reg(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
@@ -389,16 +394,17 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
 	}
 
 	ac97->capture_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_RX1;
-	ac97->capture_dma_data.wrap = 4;
-	ac97->capture_dma_data.width = 32;
-	ac97->capture_dma_data.req_sel = of_dma[1];
+	ac97->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	ac97->capture_dma_data.maxburst = 4;
+	ac97->capture_dma_data.slave_id = of_dma[1];
 
 	ac97->playback_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_TX1;
-	ac97->playback_dma_data.wrap = 4;
-	ac97->playback_dma_data.width = 32;
-	ac97->playback_dma_data.req_sel = of_dma[1];
+	ac97->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	ac97->capture_dma_data.maxburst = 4;
+	ac97->capture_dma_data.slave_id = of_dma[0];
 
-	ret = snd_soc_register_dais(&pdev->dev, &tegra20_ac97_dai, 1);
+	ret = snd_soc_register_component(&pdev->dev, &tegra20_ac97_component,
+					 &tegra20_ac97_dai, 1);
 	if (ret) {
 		dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
 		ret = -ENOMEM;
@@ -408,7 +414,7 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
 	ret = tegra_pcm_platform_register(&pdev->dev);
 	if (ret) {
 		dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
-		goto err_unregister_dai;
+		goto err_unregister_component;
 	}
 
 	ret = tegra_asoc_utils_init(&ac97->util_data, &pdev->dev);
@@ -434,8 +440,8 @@ err_asoc_utils_fini:
 	tegra_asoc_utils_fini(&ac97->util_data);
 err_unregister_pcm:
 	tegra_pcm_platform_unregister(&pdev->dev);
-err_unregister_dai:
-	snd_soc_unregister_dai(&pdev->dev);
+err_unregister_component:
+	snd_soc_unregister_component(&pdev->dev);
 err_clk_put:
 	clk_put(ac97->clk_ac97);
 err:
@@ -447,7 +453,7 @@ static int tegra20_ac97_platform_remove(struct platform_device *pdev)
 	struct tegra20_ac97 *ac97 = dev_get_drvdata(&pdev->dev);
 
 	tegra_pcm_platform_unregister(&pdev->dev);
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	tegra_asoc_utils_fini(&ac97->util_data);
 
diff --git a/sound/soc/tegra/tegra20_ac97.h b/sound/soc/tegra/tegra20_ac97.h
index dddc6828004e..4acb3aaba29b 100644
--- a/sound/soc/tegra/tegra20_ac97.h
+++ b/sound/soc/tegra/tegra20_ac97.h
@@ -85,8 +85,8 @@
 
 struct tegra20_ac97 {
 	struct clk *clk_ac97;
-	struct tegra_pcm_dma_params capture_dma_data;
-	struct tegra_pcm_dma_params playback_dma_data;
+	struct snd_dmaengine_dai_dma_data capture_dma_data;
+	struct snd_dmaengine_dai_dma_data playback_dma_data;
 	struct regmap *regmap;
 	int reset_gpio;
 	int sync_gpio;
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index caa772de5a18..52af7f6fb37f 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -41,6 +41,7 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
 #include "tegra20_i2s.h"
 
@@ -276,6 +277,10 @@ static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
 	.symmetric_rates = 1,
 };
 
+static const struct snd_soc_component_driver tegra20_i2s_component = {
+	.name		= DRV_NAME,
+};
+
 static bool tegra20_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
@@ -403,14 +408,14 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev)
 	}
 
 	i2s->capture_dma_data.addr = mem->start + TEGRA20_I2S_FIFO2;
-	i2s->capture_dma_data.wrap = 4;
-	i2s->capture_dma_data.width = 32;
-	i2s->capture_dma_data.req_sel = dma_ch;
+	i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	i2s->capture_dma_data.maxburst = 4;
+	i2s->capture_dma_data.slave_id = dma_ch;
 
 	i2s->playback_dma_data.addr = mem->start + TEGRA20_I2S_FIFO1;
-	i2s->playback_dma_data.wrap = 4;
-	i2s->playback_dma_data.width = 32;
-	i2s->playback_dma_data.req_sel = dma_ch;
+	i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	i2s->playback_dma_data.maxburst = 4;
+	i2s->playback_dma_data.slave_id = dma_ch;
 
 	pm_runtime_enable(&pdev->dev);
 	if (!pm_runtime_enabled(&pdev->dev)) {
@@ -419,7 +424,8 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev)
 			goto err_pm_disable;
 	}
 
-	ret = snd_soc_register_dai(&pdev->dev, &i2s->dai);
+	ret = snd_soc_register_component(&pdev->dev, &tegra20_i2s_component,
+					 &i2s->dai, 1);
 	if (ret) {
 		dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
 		ret = -ENOMEM;
@@ -429,13 +435,13 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev)
 	ret = tegra_pcm_platform_register(&pdev->dev);
 	if (ret) {
 		dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
-		goto err_unregister_dai;
+		goto err_unregister_component;
 	}
 
 	return 0;
 
-err_unregister_dai:
-	snd_soc_unregister_dai(&pdev->dev);
+err_unregister_component:
+	snd_soc_unregister_component(&pdev->dev);
 err_suspend:
 	if (!pm_runtime_status_suspended(&pdev->dev))
 		tegra20_i2s_runtime_suspend(&pdev->dev);
@@ -456,7 +462,7 @@ static int tegra20_i2s_platform_remove(struct platform_device *pdev)
 		tegra20_i2s_runtime_suspend(&pdev->dev);
 
 	tegra_pcm_platform_unregister(&pdev->dev);
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	clk_put(i2s->clk_i2s);
 
diff --git a/sound/soc/tegra/tegra20_i2s.h b/sound/soc/tegra/tegra20_i2s.h
index 729958713cd4..fa6c29cc12b9 100644
--- a/sound/soc/tegra/tegra20_i2s.h
+++ b/sound/soc/tegra/tegra20_i2s.h
@@ -155,8 +155,8 @@
 struct tegra20_i2s {
 	struct snd_soc_dai_driver dai;
 	struct clk *clk_i2s;
-	struct tegra_pcm_dma_params capture_dma_data;
-	struct tegra_pcm_dma_params playback_dma_data;
+	struct snd_dmaengine_dai_dma_data capture_dma_data;
+	struct snd_dmaengine_dai_dma_data playback_dma_data;
 	struct regmap *regmap;
 };
 
diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c
index 04771d14d343..5eaa12cdc6eb 100644
--- a/sound/soc/tegra/tegra20_spdif.c
+++ b/sound/soc/tegra/tegra20_spdif.c
@@ -32,6 +32,7 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
 #include "tegra20_spdif.h"
 
@@ -182,6 +183,10 @@ static struct snd_soc_dai_driver tegra20_spdif_dai = {
 	.ops = &tegra20_spdif_dai_ops,
 };
 
+static const struct snd_soc_component_driver tegra20_spdif_component = {
+	.name		= DRV_NAME,
+};
+
 static bool tegra20_spdif_wr_rd_reg(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
@@ -318,9 +323,9 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev)
 	}
 
 	spdif->playback_dma_data.addr = mem->start + TEGRA20_SPDIF_DATA_OUT;
-	spdif->playback_dma_data.wrap = 4;
-	spdif->playback_dma_data.width = 32;
-	spdif->playback_dma_data.req_sel = dmareq->start;
+	spdif->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	spdif->capture_dma_data.maxburst = 4;
+	spdif->playback_dma_data.slave_id = dmareq->start;
 
 	pm_runtime_enable(&pdev->dev);
 	if (!pm_runtime_enabled(&pdev->dev)) {
@@ -329,7 +334,8 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev)
 			goto err_pm_disable;
 	}
 
-	ret = snd_soc_register_dai(&pdev->dev, &tegra20_spdif_dai);
+	ret = snd_soc_register_component(&pdev->dev, &tegra20_spdif_component,
+				   &tegra20_spdif_dai, 1);
 	if (ret) {
 		dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
 		ret = -ENOMEM;
@@ -339,13 +345,13 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev)
 	ret = tegra_pcm_platform_register(&pdev->dev);
 	if (ret) {
 		dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
-		goto err_unregister_dai;
+		goto err_unregister_component;
 	}
 
 	return 0;
 
-err_unregister_dai:
-	snd_soc_unregister_dai(&pdev->dev);
+err_unregister_component:
+	snd_soc_unregister_component(&pdev->dev);
 err_suspend:
 	if (!pm_runtime_status_suspended(&pdev->dev))
 		tegra20_spdif_runtime_suspend(&pdev->dev);
@@ -366,7 +372,7 @@ static int tegra20_spdif_platform_remove(struct platform_device *pdev)
 		tegra20_spdif_runtime_suspend(&pdev->dev);
 
 	tegra_pcm_platform_unregister(&pdev->dev);
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	clk_put(spdif->clk_spdif_out);
 
diff --git a/sound/soc/tegra/tegra20_spdif.h b/sound/soc/tegra/tegra20_spdif.h
index b48d699fd583..85a9aefcc287 100644
--- a/sound/soc/tegra/tegra20_spdif.h
+++ b/sound/soc/tegra/tegra20_spdif.h
@@ -462,8 +462,8 @@
 
 struct tegra20_spdif {
 	struct clk *clk_spdif_out;
-	struct tegra_pcm_dma_params capture_dma_data;
-	struct tegra_pcm_dma_params playback_dma_data;
+	struct snd_dmaengine_dai_dma_data capture_dma_data;
+	struct snd_dmaengine_dai_dma_data playback_dma_data;
 	struct regmap *regmap;
 };
 
diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index e5cfb4ac41ba..23e592f453fa 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -95,8 +95,8 @@ static int tegra30_ahub_runtime_resume(struct device *dev)
 }
 
 int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
-				  unsigned long *fiforeg,
-				  unsigned long *reqsel)
+				  dma_addr_t *fiforeg,
+				  unsigned int *reqsel)
 {
 	int channel;
 	u32 reg, val;
@@ -178,8 +178,8 @@ int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif)
 EXPORT_SYMBOL_GPL(tegra30_ahub_free_rx_fifo);
 
 int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
-				  unsigned long *fiforeg,
-				  unsigned long *reqsel)
+				  dma_addr_t *fiforeg,
+				  unsigned int *reqsel)
 {
 	int channel;
 	u32 reg, val;
@@ -287,16 +287,27 @@ int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif)
 }
 EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source);
 
-static const char * const configlink_clocks[] = {
-	"i2s0",
-	"i2s1",
-	"i2s2",
-	"i2s3",
-	"i2s4",
-	"dam0",
-	"dam1",
-	"dam2",
-	"spdif_in",
+#define CLK_LIST_MASK_TEGRA30	BIT(0)
+#define CLK_LIST_MASK_TEGRA114	BIT(1)
+
+#define CLK_LIST_MASK_TEGRA30_OR_LATER \
+		(CLK_LIST_MASK_TEGRA30 | CLK_LIST_MASK_TEGRA114)
+
+static const struct {
+	const char *clk_name;
+	u32 clk_list_mask;
+} configlink_clocks[] = {
+	{ "i2s0", CLK_LIST_MASK_TEGRA30_OR_LATER },
+	{ "i2s1", CLK_LIST_MASK_TEGRA30_OR_LATER },
+	{ "i2s2", CLK_LIST_MASK_TEGRA30_OR_LATER },
+	{ "i2s3", CLK_LIST_MASK_TEGRA30_OR_LATER },
+	{ "i2s4", CLK_LIST_MASK_TEGRA30_OR_LATER },
+	{ "dam0", CLK_LIST_MASK_TEGRA30_OR_LATER },
+	{ "dam1", CLK_LIST_MASK_TEGRA30_OR_LATER },
+	{ "dam2", CLK_LIST_MASK_TEGRA30_OR_LATER },
+	{ "spdif_in", CLK_LIST_MASK_TEGRA30_OR_LATER },
+	{ "amx", CLK_LIST_MASK_TEGRA114 },
+	{ "adx", CLK_LIST_MASK_TEGRA114 },
 };
 
 #define LAST_REG(name) \
@@ -424,8 +435,24 @@ static const struct regmap_config tegra30_ahub_ahub_regmap_config = {
 	.cache_type = REGCACHE_RBTREE,
 };
 
+static struct tegra30_ahub_soc_data soc_data_tegra30 = {
+	.clk_list_mask = CLK_LIST_MASK_TEGRA30,
+};
+
+static struct tegra30_ahub_soc_data soc_data_tegra114 = {
+	.clk_list_mask = CLK_LIST_MASK_TEGRA114,
+};
+
+static const struct of_device_id tegra30_ahub_of_match[] = {
+	{ .compatible = "nvidia,tegra114-ahub", .data = &soc_data_tegra114 },
+	{ .compatible = "nvidia,tegra30-ahub",  .data = &soc_data_tegra30 },
+	{},
+};
+
 static int tegra30_ahub_probe(struct platform_device *pdev)
 {
+	const struct of_device_id *match;
+	const struct tegra30_ahub_soc_data *soc_data;
 	struct clk *clk;
 	int i;
 	struct resource *res0, *res1, *region;
@@ -436,16 +463,24 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
 	if (ahub)
 		return -ENODEV;
 
+	match = of_match_device(tegra30_ahub_of_match, &pdev->dev);
+	if (!match)
+		return -EINVAL;
+	soc_data = match->data;
+
 	/*
 	 * The AHUB hosts a register bus: the "configlink". For this to
 	 * operate correctly, all devices on this bus must be out of reset.
 	 * Ensure that here.
 	 */
 	for (i = 0; i < ARRAY_SIZE(configlink_clocks); i++) {
-		clk = clk_get(&pdev->dev, configlink_clocks[i]);
+		if (!(configlink_clocks[i].clk_list_mask &
+					soc_data->clk_list_mask))
+			continue;
+		clk = clk_get(&pdev->dev, configlink_clocks[i].clk_name);
 		if (IS_ERR(clk)) {
 			dev_err(&pdev->dev, "Can't get clock %s\n",
-				configlink_clocks[i]);
+				configlink_clocks[i].clk_name);
 			ret = PTR_ERR(clk);
 			goto err;
 		}
@@ -592,11 +627,6 @@ static int tegra30_ahub_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct of_device_id tegra30_ahub_of_match[] = {
-	{ .compatible = "nvidia,tegra30-ahub", },
-	{},
-};
-
 static const struct dev_pm_ops tegra30_ahub_pm_ops = {
 	SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend,
 			   tegra30_ahub_runtime_resume, NULL)
diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h
index e690e2eecc92..09766cdc45ca 100644
--- a/sound/soc/tegra/tegra30_ahub.h
+++ b/sound/soc/tegra/tegra30_ahub.h
@@ -451,15 +451,15 @@ enum tegra30_ahub_rxcif {
 };
 
 extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
-					 unsigned long *fiforeg,
-					 unsigned long *reqsel);
+					 dma_addr_t *fiforeg,
+					 unsigned int *reqsel);
 extern int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
 extern int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
 extern int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif);
 
 extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
-					 unsigned long *fiforeg,
-					 unsigned long *reqsel);
+					 dma_addr_t *fiforeg,
+					 unsigned int *reqsel);
 extern int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif);
 extern int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif);
 extern int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif);
@@ -468,7 +468,23 @@ extern int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif,
 					  enum tegra30_ahub_txcif txcif);
 extern int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif);
 
+struct tegra30_ahub_soc_data {
+	u32 clk_list_mask;
+	/*
+	 * FIXME: There are many more differences in HW, such as:
+	 * - More APBIF channels.
+	 * - Extra separate chunks of register address space to represent
+	 *   the extra APBIF channels.
+	 * - More units connected to the AHUB, so that tegra30_ahub_[rt]xcif
+	 *   need expansion, coupled with there being more defined bits in
+	 *   the AHUB routing registers.
+	 * However, the driver doesn't support those new features yet, so we
+	 * don't represent them here yet.
+	 */
+};
+
 struct tegra30_ahub {
+	const struct tegra30_ahub_soc_data *soc_data;
 	struct device *dev;
 	struct clk *clk_d_audio;
 	struct clk *clk_apbif;
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index f4e1ce82750a..31d092d83c71 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -38,6 +38,7 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
 #include "tegra30_ahub.h"
 #include "tegra30_i2s.h"
@@ -80,17 +81,17 @@ static int tegra30_i2s_startup(struct snd_pcm_substream *substream,
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		ret = tegra30_ahub_allocate_tx_fifo(&i2s->playback_fifo_cif,
 					&i2s->playback_dma_data.addr,
-					&i2s->playback_dma_data.req_sel);
-		i2s->playback_dma_data.wrap = 4;
-		i2s->playback_dma_data.width = 32;
+					&i2s->playback_dma_data.slave_id);
+		i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		i2s->playback_dma_data.maxburst = 4;
 		tegra30_ahub_set_rx_cif_source(i2s->playback_i2s_cif,
 					       i2s->playback_fifo_cif);
 	} else {
 		ret = tegra30_ahub_allocate_rx_fifo(&i2s->capture_fifo_cif,
 					&i2s->capture_dma_data.addr,
-					&i2s->capture_dma_data.req_sel);
-		i2s->capture_dma_data.wrap = 4;
-		i2s->capture_dma_data.width = 32;
+					&i2s->capture_dma_data.slave_id);
+		i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		i2s->capture_dma_data.maxburst = 4;
 		tegra30_ahub_set_rx_cif_source(i2s->capture_fifo_cif,
 					       i2s->capture_i2s_cif);
 	}
@@ -336,6 +337,10 @@ static const struct snd_soc_dai_driver tegra30_i2s_dai_template = {
 	.symmetric_rates = 1,
 };
 
+static const struct snd_soc_component_driver tegra30_i2s_component = {
+	.name		= DRV_NAME,
+};
+
 static bool tegra30_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
@@ -464,7 +469,8 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev)
 			goto err_pm_disable;
 	}
 
-	ret = snd_soc_register_dai(&pdev->dev, &i2s->dai);
+	ret = snd_soc_register_component(&pdev->dev, &tegra30_i2s_component,
+				   &i2s->dai, 1);
 	if (ret) {
 		dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
 		ret = -ENOMEM;
@@ -474,13 +480,13 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev)
 	ret = tegra_pcm_platform_register(&pdev->dev);
 	if (ret) {
 		dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
-		goto err_unregister_dai;
+		goto err_unregister_component;
 	}
 
 	return 0;
 
-err_unregister_dai:
-	snd_soc_unregister_dai(&pdev->dev);
+err_unregister_component:
+	snd_soc_unregister_component(&pdev->dev);
 err_suspend:
 	if (!pm_runtime_status_suspended(&pdev->dev))
 		tegra30_i2s_runtime_suspend(&pdev->dev);
@@ -501,7 +507,7 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev)
 		tegra30_i2s_runtime_suspend(&pdev->dev);
 
 	tegra_pcm_platform_unregister(&pdev->dev);
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 
 	clk_put(i2s->clk_i2s);
 
diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h
index a294d942b9f7..bea23afe3b9f 100644
--- a/sound/soc/tegra/tegra30_i2s.h
+++ b/sound/soc/tegra/tegra30_i2s.h
@@ -231,10 +231,10 @@ struct tegra30_i2s {
 	struct clk *clk_i2s;
 	enum tegra30_ahub_txcif capture_i2s_cif;
 	enum tegra30_ahub_rxcif capture_fifo_cif;
-	struct tegra_pcm_dma_params capture_dma_data;
+	struct snd_dmaengine_dai_dma_data capture_dma_data;
 	enum tegra30_ahub_rxcif playback_i2s_cif;
 	enum tegra30_ahub_txcif playback_fifo_cif;
-	struct tegra_pcm_dma_params playback_dma_data;
+	struct snd_dmaengine_dai_dma_data playback_dma_data;
 	struct regmap *regmap;
 };
 
diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c
index c80adb9da472..48d05d9e1002 100644
--- a/sound/soc/tegra/tegra_alc5632.c
+++ b/sound/soc/tegra/tegra_alc5632.c
@@ -161,20 +161,13 @@ static int tegra_alc5632_probe(struct platform_device *pdev)
 			sizeof(struct tegra_alc5632), GFP_KERNEL);
 	if (!alc5632) {
 		dev_err(&pdev->dev, "Can't allocate tegra_alc5632\n");
-		ret = -ENOMEM;
-		goto err;
+		return -ENOMEM;
 	}
 
 	card->dev = &pdev->dev;
 	platform_set_drvdata(pdev, card);
 	snd_soc_card_set_drvdata(card, alc5632);
 
-	if (!(pdev->dev.of_node)) {
-		dev_err(&pdev->dev, "Must be instantiated using device tree\n");
-		ret = -EINVAL;
-		goto err;
-	}
-
 	alc5632->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
 	if (alc5632->gpio_hp_det == -EPROBE_DEFER)
 		return -EPROBE_DEFER;
@@ -197,11 +190,11 @@ static int tegra_alc5632_probe(struct platform_device *pdev)
 		goto err;
 	}
 
-	tegra_alc5632_dai.cpu_of_node = of_parse_phandle(
-			pdev->dev.of_node, "nvidia,i2s-controller", 0);
+	tegra_alc5632_dai.cpu_of_node = of_parse_phandle(np,
+			"nvidia,i2s-controller", 0);
 	if (!tegra_alc5632_dai.cpu_of_node) {
 		dev_err(&pdev->dev,
-		"Property 'nvidia,i2s-controller' missing or invalid\n");
+			"Property 'nvidia,i2s-controller' missing or invalid\n");
 		ret = -EINVAL;
 		goto err;
 	}
diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c
index ba419f86384d..24fb001be7f4 100644
--- a/sound/soc/tegra/tegra_asoc_utils.c
+++ b/sound/soc/tegra/tegra_asoc_utils.c
@@ -43,8 +43,10 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
 	case 88200:
 		if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
 			new_baseclock = 56448000;
-		else
+		else if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA30)
 			new_baseclock = 564480000;
+		else
+			new_baseclock = 282240000;
 		break;
 	case 8000:
 	case 16000:
@@ -54,8 +56,10 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
 	case 96000:
 		if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
 			new_baseclock = 73728000;
-		else
+		else if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA30)
 			new_baseclock = 552960000;
+		else
+			new_baseclock = 368640000;
 		break;
 	default:
 		return -EINVAL;
@@ -169,6 +173,7 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
 			  struct device *dev)
 {
 	int ret;
+	bool new_clocks = false;
 
 	data->dev = dev;
 
@@ -176,28 +181,37 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
 		data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20;
 	else if (of_machine_is_compatible("nvidia,tegra30"))
 		data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA30;
-	else if (!dev->of_node)
-		/* non-DT is always Tegra20 */
-		data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20;
-	else
-		/* DT boot, but unknown SoC */
+	else if (of_machine_is_compatible("nvidia,tegra114")) {
+		data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA114;
+		new_clocks = true;
+	} else {
+		dev_err(data->dev, "SoC unknown to Tegra ASoC utils\n");
 		return -EINVAL;
+	}
 
-	data->clk_pll_a = clk_get_sys(NULL, "pll_a");
+	if (new_clocks)
+		data->clk_pll_a = clk_get(dev, "pll_a");
+	else
+		data->clk_pll_a = clk_get_sys(NULL, "pll_a");
 	if (IS_ERR(data->clk_pll_a)) {
 		dev_err(data->dev, "Can't retrieve clk pll_a\n");
 		ret = PTR_ERR(data->clk_pll_a);
 		goto err;
 	}
 
-	data->clk_pll_a_out0 = clk_get_sys(NULL, "pll_a_out0");
+	if (new_clocks)
+		data->clk_pll_a_out0 = clk_get(dev, "pll_a_out0");
+	else
+		data->clk_pll_a_out0 = clk_get_sys(NULL, "pll_a_out0");
 	if (IS_ERR(data->clk_pll_a_out0)) {
 		dev_err(data->dev, "Can't retrieve clk pll_a_out0\n");
 		ret = PTR_ERR(data->clk_pll_a_out0);
 		goto err_put_pll_a;
 	}
 
-	if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
+	if (new_clocks)
+		data->clk_cdev1 = clk_get(dev, "mclk");
+	else if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
 		data->clk_cdev1 = clk_get_sys(NULL, "cdev1");
 	else
 		data->clk_cdev1 = clk_get_sys("extern1", NULL);
diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h
index 974c9f8830f9..19fdcafed32f 100644
--- a/sound/soc/tegra/tegra_asoc_utils.h
+++ b/sound/soc/tegra/tegra_asoc_utils.h
@@ -29,6 +29,7 @@ struct device;
 enum tegra_asoc_utils_soc {
 	TEGRA_ASOC_UTILS_SOC_TEGRA20,
 	TEGRA_ASOC_UTILS_SOC_TEGRA30,
+	TEGRA_ASOC_UTILS_SOC_TEGRA114,
 };
 
 struct tegra_asoc_utils_data {
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index 5e2c55c5b255..f056f632557c 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -29,9 +29,7 @@
  *
  */
 
-#include <linux/dma-mapping.h>
 #include <linux/module.h>
-#include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -55,191 +53,24 @@ static const struct snd_pcm_hardware tegra_pcm_hardware = {
 	.fifo_size		= 4,
 };
 
-static int tegra_pcm_open(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct device *dev = rtd->platform->dev;
-	int ret;
-
-	/* Set HW params now that initialization is complete */
-	snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware);
-
-	ret = snd_dmaengine_pcm_open(substream, NULL, NULL);
-	if (ret) {
-		dev_err(dev, "dmaengine pcm open failed with err %d\n", ret);
-		return ret;
-	}
-
-	return 0;
-}
-
-static int tegra_pcm_close(struct snd_pcm_substream *substream)
-{
-	snd_dmaengine_pcm_close(substream);
-	return 0;
-}
-
-static int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct device *dev = rtd->platform->dev;
-	struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
-	struct tegra_pcm_dma_params *dmap;
-	struct dma_slave_config slave_config;
-	int ret;
-
-	dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-	ret = snd_hwparams_to_dma_slave_config(substream, params,
-						&slave_config);
-	if (ret) {
-		dev_err(dev, "hw params config failed with err %d\n", ret);
-		return ret;
-	}
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-		slave_config.dst_addr = dmap->addr;
-		slave_config.dst_maxburst = 4;
-	} else {
-		slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-		slave_config.src_addr = dmap->addr;
-		slave_config.src_maxburst = 4;
-	}
-	slave_config.slave_id = dmap->req_sel;
-
-	ret = dmaengine_slave_config(chan, &slave_config);
-	if (ret < 0) {
-		dev_err(dev, "dma slave config failed with err %d\n", ret);
-		return ret;
-	}
-
-	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-	return 0;
-}
-
-static int tegra_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-	snd_pcm_set_runtime_buffer(substream, NULL);
-	return 0;
-}
-
-static int tegra_pcm_mmap(struct snd_pcm_substream *substream,
-				struct vm_area_struct *vma)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-
-	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
-					runtime->dma_area,
-					runtime->dma_addr,
-					runtime->dma_bytes);
-}
-
-static struct snd_pcm_ops tegra_pcm_ops = {
-	.open		= tegra_pcm_open,
-	.close		= tegra_pcm_close,
-	.ioctl		= snd_pcm_lib_ioctl,
-	.hw_params	= tegra_pcm_hw_params,
-	.hw_free	= tegra_pcm_hw_free,
-	.trigger	= snd_dmaengine_pcm_trigger,
-	.pointer	= snd_dmaengine_pcm_pointer,
-	.mmap		= tegra_pcm_mmap,
-};
-
-static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
-	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-	struct snd_dma_buffer *buf = &substream->dma_buffer;
-	size_t size = tegra_pcm_hardware.buffer_bytes_max;
-
-	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
-						&buf->addr, GFP_KERNEL);
-	if (!buf->area)
-		return -ENOMEM;
-
-	buf->dev.type = SNDRV_DMA_TYPE_DEV;
-	buf->dev.dev = pcm->card->dev;
-	buf->private_data = NULL;
-	buf->bytes = size;
-
-	return 0;
-}
-
-static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
-	struct snd_pcm_substream *substream;
-	struct snd_dma_buffer *buf;
-
-	substream = pcm->streams[stream].substream;
-	if (!substream)
-		return;
-
-	buf = &substream->dma_buffer;
-	if (!buf->area)
-		return;
-
-	dma_free_writecombine(pcm->card->dev, buf->bytes,
-				buf->area, buf->addr);
-	buf->area = NULL;
-}
-
-static u64 tegra_dma_mask = DMA_BIT_MASK(32);
-
-static int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_card *card = rtd->card->snd_card;
-	struct snd_pcm *pcm = rtd->pcm;
-	int ret = 0;
-
-	if (!card->dev->dma_mask)
-		card->dev->dma_mask = &tegra_dma_mask;
-	if (!card->dev->coherent_dma_mask)
-		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
-
-	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-		ret = tegra_pcm_preallocate_dma_buffer(pcm,
-						SNDRV_PCM_STREAM_PLAYBACK);
-		if (ret)
-			goto err;
-	}
-
-	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-		ret = tegra_pcm_preallocate_dma_buffer(pcm,
-						SNDRV_PCM_STREAM_CAPTURE);
-		if (ret)
-			goto err_free_play;
-	}
-
-	return 0;
-
-err_free_play:
-	tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
-err:
-	return ret;
-}
-
-static void tegra_pcm_free(struct snd_pcm *pcm)
-{
-	tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE);
-	tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
-}
-
-static struct snd_soc_platform_driver tegra_pcm_platform = {
-	.ops		= &tegra_pcm_ops,
-	.pcm_new	= tegra_pcm_new,
-	.pcm_free	= tegra_pcm_free,
+static const struct snd_dmaengine_pcm_config tegra_dmaengine_pcm_config = {
+	.pcm_hardware = &tegra_pcm_hardware,
+	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+	.compat_filter_fn = NULL,
+	.prealloc_buffer_size = PAGE_SIZE * 8,
 };
 
 int tegra_pcm_platform_register(struct device *dev)
 {
-	return snd_soc_register_platform(dev, &tegra_pcm_platform);
+	return snd_dmaengine_pcm_register(dev, &tegra_dmaengine_pcm_config,
+			SND_DMAENGINE_PCM_FLAG_NO_DT |
+			SND_DMAENGINE_PCM_FLAG_COMPAT);
 }
 EXPORT_SYMBOL_GPL(tegra_pcm_platform_register);
 
 void tegra_pcm_platform_unregister(struct device *dev)
 {
-	snd_soc_unregister_platform(dev);
+	return snd_dmaengine_pcm_unregister(dev);
 }
 EXPORT_SYMBOL_GPL(tegra_pcm_platform_unregister);
 
diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h
index bc8b46af928e..68ad901714a9 100644
--- a/sound/soc/tegra/tegra_pcm.h
+++ b/sound/soc/tegra/tegra_pcm.h
@@ -31,13 +31,6 @@
 #ifndef __TEGRA_PCM_H__
 #define __TEGRA_PCM_H__
 
-struct tegra_pcm_dma_params {
-	unsigned long addr;
-	unsigned long wrap;
-	unsigned long width;
-	unsigned long req_sel;
-};
-
 int tegra_pcm_platform_register(struct device *dev);
 void tegra_pcm_platform_unregister(struct device *dev);
 
diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c
index c8ef88a67c59..f87fc53e9b8c 100644
--- a/sound/soc/tegra/tegra_wm8753.c
+++ b/sound/soc/tegra/tegra_wm8753.c
@@ -124,6 +124,7 @@ static struct snd_soc_card snd_soc_tegra_wm8753 = {
 
 static int tegra_wm8753_driver_probe(struct platform_device *pdev)
 {
+	struct device_node *np = pdev->dev.of_node;
 	struct snd_soc_card *card = &snd_soc_tegra_wm8753;
 	struct tegra_wm8753 *machine;
 	int ret;
@@ -132,8 +133,7 @@ static int tegra_wm8753_driver_probe(struct platform_device *pdev)
 			       GFP_KERNEL);
 	if (!machine) {
 		dev_err(&pdev->dev, "Can't allocate tegra_wm8753 struct\n");
-		ret = -ENOMEM;
-		goto err;
+		return -ENOMEM;
 	}
 
 	card->dev = &pdev->dev;
@@ -148,8 +148,8 @@ static int tegra_wm8753_driver_probe(struct platform_device *pdev)
 	if (ret)
 		goto err;
 
-	tegra_wm8753_dai.codec_of_node = of_parse_phandle(
-			pdev->dev.of_node, "nvidia,audio-codec", 0);
+	tegra_wm8753_dai.codec_of_node = of_parse_phandle(np,
+			"nvidia,audio-codec", 0);
 	if (!tegra_wm8753_dai.codec_of_node) {
 		dev_err(&pdev->dev,
 			"Property 'nvidia,audio-codec' missing or invalid\n");
@@ -157,8 +157,8 @@ static int tegra_wm8753_driver_probe(struct platform_device *pdev)
 		goto err;
 	}
 
-	tegra_wm8753_dai.cpu_of_node = of_parse_phandle(
-			pdev->dev.of_node, "nvidia,i2s-controller", 0);
+	tegra_wm8753_dai.cpu_of_node = of_parse_phandle(np,
+			"nvidia,i2s-controller", 0);
 	if (!tegra_wm8753_dai.cpu_of_node) {
 		dev_err(&pdev->dev,
 			"Property 'nvidia,i2s-controller' missing or invalid\n");
@@ -166,8 +166,7 @@ static int tegra_wm8753_driver_probe(struct platform_device *pdev)
 		goto err;
 	}
 
-	tegra_wm8753_dai.platform_of_node =
-				tegra_wm8753_dai.cpu_of_node;
+	tegra_wm8753_dai.platform_of_node = tegra_wm8753_dai.cpu_of_node;
 
 	ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
 	if (ret)
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index bbd79bf56303..4ac73730d79a 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -39,7 +39,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/tegra_wm8903.h>
 
 #include "../codecs/wm8903.h"
 
@@ -48,7 +47,11 @@
 #define DRV_NAME "tegra-snd-wm8903"
 
 struct tegra_wm8903 {
-	struct tegra_wm8903_platform_data pdata;
+	int gpio_spkr_en;
+	int gpio_hp_det;
+	int gpio_hp_mute;
+	int gpio_int_mic_en;
+	int gpio_ext_mic_en;
 	struct tegra_asoc_utils_data util_data;
 };
 
@@ -129,12 +132,11 @@ static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w,
 	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 (!gpio_is_valid(pdata->gpio_spkr_en))
+	if (!gpio_is_valid(machine->gpio_spkr_en))
 		return 0;
 
-	gpio_set_value_cansleep(pdata->gpio_spkr_en,
+	gpio_set_value_cansleep(machine->gpio_spkr_en,
 				SND_SOC_DAPM_EVENT_ON(event));
 
 	return 0;
@@ -146,12 +148,11 @@ static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w,
 	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 (!gpio_is_valid(pdata->gpio_hp_mute))
+	if (!gpio_is_valid(machine->gpio_hp_mute))
 		return 0;
 
-	gpio_set_value_cansleep(pdata->gpio_hp_mute,
+	gpio_set_value_cansleep(machine->gpio_hp_mute,
 				!SND_SOC_DAPM_EVENT_ON(event));
 
 	return 0;
@@ -163,17 +164,6 @@ static const struct snd_soc_dapm_widget tegra_wm8903_dapm_widgets[] = {
 	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 Jack", NULL, "MICBIAS"},
-	{"IN1L", NULL, "Mic Jack"},
-};
-
 static const struct snd_kcontrol_new tegra_wm8903_controls[] = {
 	SOC_DAPM_PIN_SWITCH("Int Spk"),
 };
@@ -185,10 +175,9 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
 	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;
 
-	if (gpio_is_valid(pdata->gpio_hp_det)) {
-		tegra_wm8903_hp_jack_gpio.gpio = pdata->gpio_hp_det;
+	if (gpio_is_valid(machine->gpio_hp_det)) {
+		tegra_wm8903_hp_jack_gpio.gpio = machine->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,
@@ -226,9 +215,6 @@ static int tegra_wm8903_remove(struct snd_soc_card *card)
 static struct snd_soc_dai_link tegra_wm8903_dai = {
 	.name = "WM8903",
 	.stream_name = "WM8903 PCM",
-	.codec_name = "wm8903.0-001a",
-	.platform_name = "tegra20-i2s.0",
-	.cpu_dai_name = "tegra20-i2s.0",
 	.codec_dai_name = "wm8903-hifi",
 	.init = tegra_wm8903_init,
 	.ops = &tegra_wm8903_ops,
@@ -257,96 +243,25 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev)
 	struct device_node *np = pdev->dev.of_node;
 	struct snd_soc_card *card = &snd_soc_tegra_wm8903;
 	struct tegra_wm8903 *machine;
-	struct tegra_wm8903_platform_data *pdata;
 	int ret;
 
-	if (!pdev->dev.platform_data && !pdev->dev.of_node) {
-		dev_err(&pdev->dev, "No platform data supplied\n");
-		return -EINVAL;
-	}
-
 	machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm8903),
 			       GFP_KERNEL);
 	if (!machine) {
 		dev_err(&pdev->dev, "Can't allocate tegra_wm8903 struct\n");
-		ret = -ENOMEM;
-		goto err;
+		return -ENOMEM;
 	}
-	pdata = &machine->pdata;
 
 	card->dev = &pdev->dev;
 	platform_set_drvdata(pdev, card);
 	snd_soc_card_set_drvdata(card, machine);
 
-	if (pdev->dev.platform_data) {
-		memcpy(pdata, card->dev->platform_data, sizeof(*pdata));
-	} else if (np) {
-		pdata->gpio_spkr_en = of_get_named_gpio(np,
-						"nvidia,spkr-en-gpios", 0);
-		if (pdata->gpio_spkr_en == -EPROBE_DEFER)
-			return -EPROBE_DEFER;
-
-		pdata->gpio_hp_mute = of_get_named_gpio(np,
-						"nvidia,hp-mute-gpios", 0);
-		if (pdata->gpio_hp_mute == -EPROBE_DEFER)
-			return -EPROBE_DEFER;
-
-		pdata->gpio_hp_det = of_get_named_gpio(np,
-						"nvidia,hp-det-gpios", 0);
-		if (pdata->gpio_hp_det == -EPROBE_DEFER)
-			return -EPROBE_DEFER;
-
-		pdata->gpio_int_mic_en = of_get_named_gpio(np,
-						"nvidia,int-mic-en-gpios", 0);
-		if (pdata->gpio_int_mic_en == -EPROBE_DEFER)
-			return -EPROBE_DEFER;
-
-		pdata->gpio_ext_mic_en = of_get_named_gpio(np,
-						"nvidia,ext-mic-en-gpios", 0);
-		if (pdata->gpio_ext_mic_en == -EPROBE_DEFER)
-			return -EPROBE_DEFER;
-	}
-
-	if (np) {
-		ret = snd_soc_of_parse_card_name(card, "nvidia,model");
-		if (ret)
-			goto err;
-
-		ret = snd_soc_of_parse_audio_routing(card,
-						     "nvidia,audio-routing");
-		if (ret)
-			goto err;
-
-		tegra_wm8903_dai.codec_name = NULL;
-		tegra_wm8903_dai.codec_of_node = of_parse_phandle(np,
-				"nvidia,audio-codec", 0);
-		if (!tegra_wm8903_dai.codec_of_node) {
-			dev_err(&pdev->dev,
-				"Property 'nvidia,audio-codec' missing or invalid\n");
-			ret = -EINVAL;
-			goto err;
-		}
-
-		tegra_wm8903_dai.cpu_dai_name = NULL;
-		tegra_wm8903_dai.cpu_of_node = of_parse_phandle(np,
-				"nvidia,i2s-controller", 0);
-		if (!tegra_wm8903_dai.cpu_of_node) {
-			dev_err(&pdev->dev,
-				"Property 'nvidia,i2s-controller' missing or invalid\n");
-			ret = -EINVAL;
-			goto err;
-		}
-
-		tegra_wm8903_dai.platform_name = NULL;
-		tegra_wm8903_dai.platform_of_node =
-					tegra_wm8903_dai.cpu_of_node;
-	} else {
-		card->dapm_routes = harmony_audio_map;
-		card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map);
-	}
-
-	if (gpio_is_valid(pdata->gpio_spkr_en)) {
-		ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_spkr_en,
+	machine->gpio_spkr_en = of_get_named_gpio(np, "nvidia,spkr-en-gpios",
+						  0);
+	if (machine->gpio_spkr_en == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+	if (gpio_is_valid(machine->gpio_spkr_en)) {
+		ret = devm_gpio_request_one(&pdev->dev, machine->gpio_spkr_en,
 					    GPIOF_OUT_INIT_LOW, "spkr_en");
 		if (ret) {
 			dev_err(card->dev, "cannot get spkr_en gpio\n");
@@ -354,8 +269,12 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev)
 		}
 	}
 
-	if (gpio_is_valid(pdata->gpio_hp_mute)) {
-		ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_hp_mute,
+	machine->gpio_hp_mute = of_get_named_gpio(np, "nvidia,hp-mute-gpios",
+						  0);
+	if (machine->gpio_hp_mute == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+	if (gpio_is_valid(machine->gpio_hp_mute)) {
+		ret = devm_gpio_request_one(&pdev->dev, machine->gpio_hp_mute,
 					    GPIOF_OUT_INIT_HIGH, "hp_mute");
 		if (ret) {
 			dev_err(card->dev, "cannot get hp_mute gpio\n");
@@ -363,9 +282,18 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev)
 		}
 	}
 
-	if (gpio_is_valid(pdata->gpio_int_mic_en)) {
+	machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
+	if (machine->gpio_hp_det == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+
+	machine->gpio_int_mic_en = of_get_named_gpio(np,
+						"nvidia,int-mic-en-gpios", 0);
+	if (machine->gpio_int_mic_en == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+	if (gpio_is_valid(machine->gpio_int_mic_en)) {
 		/* Disable int mic; enable signal is active-high */
-		ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_int_mic_en,
+		ret = devm_gpio_request_one(&pdev->dev,
+					    machine->gpio_int_mic_en,
 					    GPIOF_OUT_INIT_LOW, "int_mic_en");
 		if (ret) {
 			dev_err(card->dev, "cannot get int_mic_en gpio\n");
@@ -373,9 +301,14 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev)
 		}
 	}
 
-	if (gpio_is_valid(pdata->gpio_ext_mic_en)) {
+	machine->gpio_ext_mic_en = of_get_named_gpio(np,
+						"nvidia,ext-mic-en-gpios", 0);
+	if (machine->gpio_ext_mic_en == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+	if (gpio_is_valid(machine->gpio_ext_mic_en)) {
 		/* Enable ext mic; enable signal is active-low */
-		ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_ext_mic_en,
+		ret = devm_gpio_request_one(&pdev->dev,
+					    machine->gpio_ext_mic_en,
 					    GPIOF_OUT_INIT_LOW, "ext_mic_en");
 		if (ret) {
 			dev_err(card->dev, "cannot get ext_mic_en gpio\n");
@@ -383,6 +316,34 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev)
 		}
 	}
 
+	ret = snd_soc_of_parse_card_name(card, "nvidia,model");
+	if (ret)
+		goto err;
+
+	ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
+	if (ret)
+		goto err;
+
+	tegra_wm8903_dai.codec_of_node = of_parse_phandle(np,
+						"nvidia,audio-codec", 0);
+	if (!tegra_wm8903_dai.codec_of_node) {
+		dev_err(&pdev->dev,
+			"Property 'nvidia,audio-codec' missing or invalid\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	tegra_wm8903_dai.cpu_of_node = of_parse_phandle(np,
+			"nvidia,i2s-controller", 0);
+	if (!tegra_wm8903_dai.cpu_of_node) {
+		dev_err(&pdev->dev,
+			"Property 'nvidia,i2s-controller' missing or invalid\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	tegra_wm8903_dai.platform_of_node = tegra_wm8903_dai.cpu_of_node;
+
 	ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
 	if (ret)
 		goto err;
diff --git a/sound/soc/tegra/tegra_wm9712.c b/sound/soc/tegra/tegra_wm9712.c
index 68d42403d9b5..5e119630b0e0 100644
--- a/sound/soc/tegra/tegra_wm9712.c
+++ b/sound/soc/tegra/tegra_wm9712.c
@@ -55,7 +55,7 @@ static int tegra_wm9712_init(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_dai_link tegra_wm9712_dai = {
 	.name = "AC97 HiFi",
 	.stream_name = "AC97 HiFi",
-	.cpu_dai_name = "tegra-ac97-pcm",
+	.cpu_dai_name = "tegra20-ac97",
 	.codec_dai_name = "wm9712-hifi",
 	.codec_name = "wm9712-codec",
 	.init = tegra_wm9712_init,
@@ -79,11 +79,6 @@ static int tegra_wm9712_driver_probe(struct platform_device *pdev)
 	struct tegra_wm9712 *machine;
 	int ret;
 
-	if (!pdev->dev.of_node) {
-		dev_err(&pdev->dev, "No platform data supplied\n");
-		return -EINVAL;
-	}
-
 	machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm9712),
 			       GFP_KERNEL);
 	if (!machine) {
diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c
index 7fcf6c2297db..05c68aab5cf0 100644
--- a/sound/soc/tegra/trimslice.c
+++ b/sound/soc/tegra/trimslice.c
@@ -97,9 +97,6 @@ static const struct snd_soc_dapm_route trimslice_audio_map[] = {
 static struct snd_soc_dai_link trimslice_tlv320aic23_dai = {
 	.name = "TLV320AIC23",
 	.stream_name = "AIC23",
-	.codec_name = "tlv320aic23-codec.2-001a",
-	.platform_name = "tegra20-i2s.0",
-	.cpu_dai_name = "tegra20-i2s.0",
 	.codec_dai_name = "tlv320aic23-hifi",
 	.ops = &trimslice_asoc_ops,
 	.dai_fmt = SND_SOC_DAIFMT_I2S |
@@ -122,6 +119,7 @@ static struct snd_soc_card snd_soc_trimslice = {
 
 static int tegra_snd_trimslice_probe(struct platform_device *pdev)
 {
+	struct device_node *np = pdev->dev.of_node;
 	struct snd_soc_card *card = &snd_soc_trimslice;
 	struct tegra_trimslice *trimslice;
 	int ret;
@@ -130,44 +128,38 @@ static int tegra_snd_trimslice_probe(struct platform_device *pdev)
 				 GFP_KERNEL);
 	if (!trimslice) {
 		dev_err(&pdev->dev, "Can't allocate tegra_trimslice\n");
-		ret = -ENOMEM;
+		return -ENOMEM;
+	}
+
+	card->dev = &pdev->dev;
+	platform_set_drvdata(pdev, card);
+	snd_soc_card_set_drvdata(card, trimslice);
+
+	trimslice_tlv320aic23_dai.codec_of_node = of_parse_phandle(np,
+			"nvidia,audio-codec", 0);
+	if (!trimslice_tlv320aic23_dai.codec_of_node) {
+		dev_err(&pdev->dev,
+			"Property 'nvidia,audio-codec' missing or invalid\n");
+		ret = -EINVAL;
 		goto err;
 	}
 
-	if (pdev->dev.of_node) {
-		trimslice_tlv320aic23_dai.codec_name = NULL;
-		trimslice_tlv320aic23_dai.codec_of_node = of_parse_phandle(
-				pdev->dev.of_node, "nvidia,audio-codec", 0);
-		if (!trimslice_tlv320aic23_dai.codec_of_node) {
-			dev_err(&pdev->dev,
-				"Property 'nvidia,audio-codec' missing or invalid\n");
-			ret = -EINVAL;
-			goto err;
-		}
-
-		trimslice_tlv320aic23_dai.cpu_dai_name = NULL;
-		trimslice_tlv320aic23_dai.cpu_of_node = of_parse_phandle(
-				pdev->dev.of_node, "nvidia,i2s-controller", 0);
-		if (!trimslice_tlv320aic23_dai.cpu_of_node) {
-			dev_err(&pdev->dev,
-				"Property 'nvidia,i2s-controller' missing or invalid\n");
-			ret = -EINVAL;
-			goto err;
-		}
-
-		trimslice_tlv320aic23_dai.platform_name = NULL;
-		trimslice_tlv320aic23_dai.platform_of_node =
-				trimslice_tlv320aic23_dai.cpu_of_node;
+	trimslice_tlv320aic23_dai.cpu_of_node = of_parse_phandle(np,
+			"nvidia,i2s-controller", 0);
+	if (!trimslice_tlv320aic23_dai.cpu_of_node) {
+		dev_err(&pdev->dev,
+			"Property 'nvidia,i2s-controller' missing or invalid\n");
+		ret = -EINVAL;
+		goto err;
 	}
 
+	trimslice_tlv320aic23_dai.platform_of_node =
+			trimslice_tlv320aic23_dai.cpu_of_node;
+
 	ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev);
 	if (ret)
 		goto err;
 
-	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",
diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c
index 16ab69635e2e..8a2840304d28 100644
--- a/sound/soc/txx9/txx9aclc-ac97.c
+++ b/sound/soc/txx9/txx9aclc-ac97.c
@@ -170,6 +170,10 @@ static struct snd_soc_dai_driver txx9aclc_ac97_dai = {
 	},
 };
 
+static const struct snd_soc_component_driver txx9aclc_ac97_component = {
+	.name		= "txx9aclc-ac97",
+};
+
 static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
 {
 	struct txx9aclc_plat_drvdata *drvdata;
@@ -205,12 +209,13 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
 	if (err < 0)
 		return err;
 
-	return snd_soc_register_dai(&pdev->dev, &txx9aclc_ac97_dai);
+	return snd_soc_register_component(&pdev->dev, &txx9aclc_ac97_component,
+					  &txx9aclc_ac97_dai, 1);
 }
 
 static int txx9aclc_ac97_dev_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
 	return 0;
 }
 
diff --git a/sound/soc/ux500/Kconfig b/sound/soc/ux500/Kconfig
index 6b799c0e88df..aa5011894c74 100644
--- a/sound/soc/ux500/Kconfig
+++ b/sound/soc/ux500/Kconfig
@@ -16,7 +16,7 @@ config SND_SOC_UX500_PLAT_MSP_I2S
 config SND_SOC_UX500_PLAT_DMA
 	tristate "Platform - DB8500 (DMA)"
 	depends on SND_SOC_UX500
-	select SND_SOC_DMAENGINE_PCM
+	select SND_SOC_GENERIC_DMAENGINE_PCM
 	help
 		Say Y if you want to enable the Ux500 platform-driver.
 
diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c
index 54028cf76511..7d5fc1328523 100644
--- a/sound/soc/ux500/ux500_msp_dai.c
+++ b/sound/soc/ux500/ux500_msp_dai.c
@@ -766,6 +766,11 @@ static struct snd_soc_dai_driver ux500_msp_dai_drv[UX500_NBR_OF_DAI] = {
 	},
 };
 
+static const struct snd_soc_component_driver ux500_msp_component = {
+	.name		= "ux500-msp",
+};
+
+
 static int ux500_msp_drv_probe(struct platform_device *pdev)
 {
 	struct ux500_msp_i2s_drvdata *drvdata;
@@ -823,8 +828,8 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
 	}
 	dev_set_drvdata(&pdev->dev, drvdata);
 
-	ret = snd_soc_register_dai(&pdev->dev,
-				&ux500_msp_dai_drv[drvdata->msp->id]);
+	ret = snd_soc_register_component(&pdev->dev, &ux500_msp_component,
+					 &ux500_msp_dai_drv[drvdata->msp->id], 1);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Error: %s: Failed to register MSP%d!\n",
 			__func__, drvdata->msp->id);
@@ -842,7 +847,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
 	return 0;
 
 err_reg_plat:
-	snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(ux500_msp_dai_drv));
+	snd_soc_unregister_component(&pdev->dev);
 err_init_msp:
 	clk_put(drvdata->clk);
 err_clk:
@@ -859,7 +864,7 @@ static int ux500_msp_drv_remove(struct platform_device *pdev)
 
 	ux500_pcm_unregister_platform(pdev);
 
-	snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(ux500_msp_dai_drv));
+	snd_soc_unregister_component(&pdev->dev);
 
 	devm_regulator_put(drvdata->reg_vape);
 	prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s");
diff --git a/sound/soc/ux500/ux500_msp_dai.h b/sound/soc/ux500/ux500_msp_dai.h
index 9c778d9c3838..f53104359f15 100644
--- a/sound/soc/ux500/ux500_msp_dai.h
+++ b/sound/soc/ux500/ux500_msp_dai.h
@@ -35,13 +35,8 @@
 #define FRAME_PER_8_SLOTS				138
 #define FRAME_PER_16_SLOTS				277
 
-#ifndef CONFIG_SND_SOC_UX500_AB5500
 #define UX500_MSP_INTERNAL_CLOCK_FREQ  40000000
 #define UX500_MSP1_INTERNAL_CLOCK_FREQ UX500_MSP_INTERNAL_CLOCK_FREQ
-#else
-#define UX500_MSP_INTERNAL_CLOCK_FREQ 13000000
-#define UX500_MSP1_INTERNAL_CLOCK_FREQ (UX500_MSP_INTERNAL_CLOCK_FREQ * 2)
-#endif
 
 #define UX500_MSP_MIN_CHANNELS		1
 #define UX500_MSP_MAX_CHANNELS		8
diff --git a/sound/soc/ux500/ux500_msp_i2s.h b/sound/soc/ux500/ux500_msp_i2s.h
index 437f0c032c58..e5cd105c90f9 100644
--- a/sound/soc/ux500/ux500_msp_i2s.h
+++ b/sound/soc/ux500/ux500_msp_i2s.h
@@ -541,6 +541,7 @@ struct ux500_msp_dma_params {
 	struct stedma40_chan_cfg *dma_cfg;
 };
 
+struct msp_i2s_platform_data;
 int ux500_msp_i2s_init_msp(struct platform_device *pdev,
 			struct ux500_msp **msp_p,
 			struct msp_i2s_platform_data *platform_data);
diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c
index 846fa82a58d0..b6e5ae277299 100644
--- a/sound/soc/ux500/ux500_pcm.c
+++ b/sound/soc/ux500/ux500_pcm.c
@@ -28,28 +28,19 @@
 #include "ux500_msp_i2s.h"
 #include "ux500_pcm.h"
 
-static struct snd_pcm_hardware ux500_pcm_hw_playback = {
-	.info = SNDRV_PCM_INFO_INTERLEAVED |
-		SNDRV_PCM_INFO_MMAP |
-		SNDRV_PCM_INFO_RESUME |
-		SNDRV_PCM_INFO_PAUSE,
-	.formats = SNDRV_PCM_FMTBIT_S16_LE |
-		SNDRV_PCM_FMTBIT_U16_LE |
-		SNDRV_PCM_FMTBIT_S16_BE |
-		SNDRV_PCM_FMTBIT_U16_BE,
-	.rates = SNDRV_PCM_RATE_KNOT,
-	.rate_min = UX500_PLATFORM_MIN_RATE_PLAYBACK,
-	.rate_max = UX500_PLATFORM_MAX_RATE_PLAYBACK,
-	.channels_min = UX500_PLATFORM_MIN_CHANNELS,
-	.channels_max = UX500_PLATFORM_MAX_CHANNELS,
-	.buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX,
-	.period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN,
-	.period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX,
-	.periods_min = UX500_PLATFORM_PERIODS_MIN,
-	.periods_max = UX500_PLATFORM_PERIODS_MAX,
-};
+#define UX500_PLATFORM_MIN_RATE 8000
+#define UX500_PLATFORM_MAX_RATE 48000
+
+#define UX500_PLATFORM_MIN_CHANNELS 1
+#define UX500_PLATFORM_MAX_CHANNELS 8
 
-static struct snd_pcm_hardware ux500_pcm_hw_capture = {
+#define UX500_PLATFORM_PERIODS_BYTES_MIN	128
+#define UX500_PLATFORM_PERIODS_BYTES_MAX	(64 * PAGE_SIZE)
+#define UX500_PLATFORM_PERIODS_MIN		2
+#define UX500_PLATFORM_PERIODS_MAX		48
+#define UX500_PLATFORM_BUFFER_BYTES_MAX		(2048 * PAGE_SIZE)
+
+static const struct snd_pcm_hardware ux500_pcm_hw = {
 	.info = SNDRV_PCM_INFO_INTERLEAVED |
 		SNDRV_PCM_INFO_MMAP |
 		SNDRV_PCM_INFO_RESUME |
@@ -59,8 +50,8 @@ static struct snd_pcm_hardware ux500_pcm_hw_capture = {
 		SNDRV_PCM_FMTBIT_S16_BE |
 		SNDRV_PCM_FMTBIT_U16_BE,
 	.rates = SNDRV_PCM_RATE_KNOT,
-	.rate_min = UX500_PLATFORM_MIN_RATE_CAPTURE,
-	.rate_max = UX500_PLATFORM_MAX_RATE_CAPTURE,
+	.rate_min = UX500_PLATFORM_MIN_RATE,
+	.rate_max = UX500_PLATFORM_MAX_RATE,
 	.channels_min = UX500_PLATFORM_MIN_CHANNELS,
 	.channels_max = UX500_PLATFORM_MAX_CHANNELS,
 	.buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX,
@@ -70,64 +61,23 @@ static struct snd_pcm_hardware ux500_pcm_hw_capture = {
 	.periods_max = UX500_PLATFORM_PERIODS_MAX,
 };
 
-static void ux500_pcm_dma_hw_free(struct device *dev,
-				struct snd_pcm_substream *substream)
+static struct dma_chan *ux500_pcm_request_chan(struct snd_soc_pcm_runtime *rtd,
+	struct snd_pcm_substream *substream)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_dma_buffer *buf = runtime->dma_buffer_p;
-
-	if (runtime->dma_area == NULL)
-		return;
-
-	if (buf != &substream->dma_buffer) {
-		dma_free_coherent(buf->dev.dev, buf->bytes, buf->area,
-				buf->addr);
-		kfree(runtime->dma_buffer_p);
-	}
-
-	snd_pcm_set_runtime_buffer(substream, NULL);
-}
-
-static int ux500_pcm_open(struct snd_pcm_substream *substream)
-{
-	int stream_id = substream->pstr->stream;
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *dai = rtd->cpu_dai;
 	struct device *dev = dai->dev;
-	int ret;
-	struct ux500_msp_dma_params *dma_params;
 	u16 per_data_width, mem_data_width;
 	struct stedma40_chan_cfg *dma_cfg;
+	struct ux500_msp_dma_params *dma_params;
 
 	dev_dbg(dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id,
 		snd_pcm_stream_str(substream));
 
-	dev_dbg(dev, "%s: Set runtime hwparams.\n", __func__);
-	if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
-		snd_soc_set_runtime_hwparams(substream,
-					&ux500_pcm_hw_playback);
-	else
-		snd_soc_set_runtime_hwparams(substream,
-					&ux500_pcm_hw_capture);
-
-	/* ensure that buffer size is a multiple of period size */
-	ret = snd_pcm_hw_constraint_integer(runtime,
-					SNDRV_PCM_HW_PARAM_PERIODS);
-	if (ret < 0) {
-		dev_err(dev, "%s: Error: snd_pcm_hw_constraints failed (%d)\n",
-			__func__, ret);
-		return ret;
-	}
-
-	dev_dbg(dev, "%s: Set hw-struct for %s.\n", __func__,
-		snd_pcm_stream_str(substream));
-	runtime->hw = (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ?
-		ux500_pcm_hw_playback : ux500_pcm_hw_capture;
+	dma_params = snd_soc_dai_get_dma_data(dai, substream);
+	dma_cfg = dma_params->dma_cfg;
 
 	mem_data_width = STEDMA40_HALFWORD_WIDTH;
 
-	dma_params = snd_soc_dai_get_dma_data(dai, substream);
 	switch (dma_params->data_size) {
 	case 32:
 		per_data_width = STEDMA40_WORD_WIDTH;
@@ -140,13 +90,8 @@ static int ux500_pcm_open(struct snd_pcm_substream *substream)
 		break;
 	default:
 		per_data_width = STEDMA40_WORD_WIDTH;
-		dev_warn(rtd->platform->dev,
-			"%s: Unknown data-size (%d)! Assuming 32 bits.\n",
-			__func__, dma_params->data_size);
 	}
 
-	dma_cfg = dma_params->dma_cfg;
-
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		dma_cfg->src_info.data_width = mem_data_width;
 		dma_cfg->dst_info.data_width = per_data_width;
@@ -155,137 +100,24 @@ static int ux500_pcm_open(struct snd_pcm_substream *substream)
 		dma_cfg->dst_info.data_width = mem_data_width;
 	}
 
-
-	ret = snd_dmaengine_pcm_open(substream, stedma40_filter, dma_cfg);
-	if (ret) {
-		dev_dbg(dai->dev,
-			"%s: ERROR: snd_dmaengine_pcm_open failed (%d)!\n",
-			__func__, ret);
-		return ret;
-	}
-
-	snd_dmaengine_pcm_set_data(substream, dma_cfg);
-
-	return 0;
-}
-
-static int ux500_pcm_close(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *dai = rtd->cpu_dai;
-
-	dev_dbg(dai->dev, "%s: Enter\n", __func__);
-
-	snd_dmaengine_pcm_close(substream);
-
-	return 0;
-}
-
-static int ux500_pcm_hw_params(struct snd_pcm_substream *substream,
-			struct snd_pcm_hw_params *hw_params)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_dma_buffer *buf = runtime->dma_buffer_p;
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	int ret = 0;
-	int size;
-
-	dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__);
-
-	size = params_buffer_bytes(hw_params);
-
-	if (buf) {
-		if (buf->bytes >= size)
-			goto out;
-		ux500_pcm_dma_hw_free(NULL, substream);
-	}
-
-	if (substream->dma_buffer.area != NULL &&
-		substream->dma_buffer.bytes >= size) {
-		buf = &substream->dma_buffer;
-	} else {
-		buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL);
-		if (!buf)
-			goto nomem;
-
-		buf->dev.type = SNDRV_DMA_TYPE_DEV;
-		buf->dev.dev = NULL;
-		buf->area = dma_alloc_coherent(NULL, size, &buf->addr,
-					GFP_KERNEL);
-		buf->bytes = size;
-		buf->private_data = NULL;
-
-		if (!buf->area)
-			goto free;
-	}
-	snd_pcm_set_runtime_buffer(substream, buf);
-	ret = 1;
- out:
-	runtime->dma_bytes = size;
-	return ret;
-
- free:
-	kfree(buf);
- nomem:
-	return -ENOMEM;
+	return snd_dmaengine_pcm_request_channel(stedma40_filter, dma_cfg);
 }
 
-static int ux500_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-
-	dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__);
-
-	ux500_pcm_dma_hw_free(NULL, substream);
-
-	return 0;
-}
-
-static int ux500_pcm_mmap(struct snd_pcm_substream *substream,
-			struct vm_area_struct *vma)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-
-	dev_dbg(rtd->platform->dev, "%s: Enter.\n", __func__);
-
-	return dma_mmap_coherent(NULL, vma, runtime->dma_area,
-				runtime->dma_addr, runtime->dma_bytes);
-}
-
-static struct snd_pcm_ops ux500_pcm_ops = {
-	.open		= ux500_pcm_open,
-	.close		= ux500_pcm_close,
-	.ioctl		= snd_pcm_lib_ioctl,
-	.hw_params	= ux500_pcm_hw_params,
-	.hw_free	= ux500_pcm_hw_free,
-	.trigger	= snd_dmaengine_pcm_trigger,
-	.pointer	= snd_dmaengine_pcm_pointer_no_residue,
-	.mmap		= ux500_pcm_mmap
-};
-
-int ux500_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_pcm *pcm = rtd->pcm;
-
-	dev_dbg(rtd->platform->dev, "%s: Enter (id = '%s').\n", __func__,
-		pcm->id);
-
-	pcm->info_flags = 0;
-
-	return 0;
-}
-
-static struct snd_soc_platform_driver ux500_pcm_soc_drv = {
-	.ops		= &ux500_pcm_ops,
-	.pcm_new        = ux500_pcm_new,
+static const struct snd_dmaengine_pcm_config ux500_dmaengine_pcm_config = {
+	.pcm_hardware = &ux500_pcm_hw,
+	.compat_request_channel = ux500_pcm_request_chan,
+	.prealloc_buffer_size = 128 * 1024,
 };
 
 int ux500_pcm_register_platform(struct platform_device *pdev)
 {
 	int ret;
 
-	ret = snd_soc_register_platform(&pdev->dev, &ux500_pcm_soc_drv);
+	ret = snd_dmaengine_pcm_register(&pdev->dev,
+			&ux500_dmaengine_pcm_config,
+			SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
+			SND_DMAENGINE_PCM_FLAG_COMPAT |
+			SND_DMAENGINE_PCM_FLAG_NO_DT);
 	if (ret < 0) {
 		dev_err(&pdev->dev,
 			"%s: ERROR: Failed to register platform '%s' (%d)!\n",
@@ -299,8 +131,7 @@ EXPORT_SYMBOL_GPL(ux500_pcm_register_platform);
 
 int ux500_pcm_unregister_platform(struct platform_device *pdev)
 {
-	snd_soc_unregister_platform(&pdev->dev);
-
+	snd_dmaengine_pcm_unregister(&pdev->dev);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform);
diff --git a/sound/soc/ux500/ux500_pcm.h b/sound/soc/ux500/ux500_pcm.h
index 76d344476afc..d76e1aff6458 100644
--- a/sound/soc/ux500/ux500_pcm.h
+++ b/sound/soc/ux500/ux500_pcm.h
@@ -18,20 +18,6 @@
 
 #include <linux/workqueue.h>
 
-#define UX500_PLATFORM_MIN_RATE_PLAYBACK 8000
-#define UX500_PLATFORM_MAX_RATE_PLAYBACK 48000
-#define UX500_PLATFORM_MIN_RATE_CAPTURE	8000
-#define UX500_PLATFORM_MAX_RATE_CAPTURE	48000
-
-#define UX500_PLATFORM_MIN_CHANNELS 1
-#define UX500_PLATFORM_MAX_CHANNELS 8
-
-#define UX500_PLATFORM_PERIODS_BYTES_MIN	128
-#define UX500_PLATFORM_PERIODS_BYTES_MAX	(64 * PAGE_SIZE)
-#define UX500_PLATFORM_PERIODS_MIN		2
-#define UX500_PLATFORM_PERIODS_MAX		48
-#define UX500_PLATFORM_BUFFER_BYTES_MAX		(2048 * PAGE_SIZE)
-
 int ux500_pcm_register_platform(struct platform_device *pdev);
 int ux500_pcm_unregister_platform(struct platform_device *pdev);
 
diff --git a/sound/sound_core.c b/sound/sound_core.c
index bb23009edc8d..359753fc24e1 100644
--- a/sound/sound_core.c
+++ b/sound/sound_core.c
@@ -352,7 +352,9 @@ static struct sound_unit *chains[SOUND_STEP];
  *      @dev: device pointer
  *
  *	Allocate a special sound device by minor number from the sound
- *	subsystem. The allocated number is returned on success. On failure
+ *	subsystem.
+ *
+ *	Return: The allocated number is returned on success. On failure,
  *	a negative error code is returned.
  */
  
@@ -436,8 +438,10 @@ EXPORT_SYMBOL(register_sound_special);
  *	@dev: Unit number to allocate
  *
  *	Allocate a mixer device. Unit is the number of the mixer requested.
- *	Pass -1 to request the next free mixer unit. On success the allocated
- *	number is returned, on failure a negative error code is returned.
+ *	Pass -1 to request the next free mixer unit.
+ *
+ *	Return: On success, the allocated number is returned. On failure,
+ *	a negative error code is returned.
  */
 
 int register_sound_mixer(const struct file_operations *fops, int dev)
@@ -454,8 +458,10 @@ EXPORT_SYMBOL(register_sound_mixer);
  *	@dev: Unit number to allocate
  *
  *	Allocate a midi device. Unit is the number of the midi device requested.
- *	Pass -1 to request the next free midi unit. On success the allocated
- *	number is returned, on failure a negative error code is returned.
+ *	Pass -1 to request the next free midi unit.
+ *
+ *	Return: On success, the allocated number is returned. On failure,
+ *	a negative error code is returned.
  */
 
 int register_sound_midi(const struct file_operations *fops, int dev)
@@ -477,11 +483,13 @@ EXPORT_SYMBOL(register_sound_midi);
  *	@dev: Unit number to allocate
  *
  *	Allocate a DSP device. Unit is the number of the DSP requested.
- *	Pass -1 to request the next free DSP unit. On success the allocated
- *	number is returned, on failure a negative error code is returned.
+ *	Pass -1 to request the next free DSP unit.
  *
  *	This function allocates both the audio and dsp device entries together
  *	and will always allocate them as a matching pair - eg dsp3/audio3
+ *
+ *	Return: On success, the allocated number is returned. On failure,
+ *	a negative error code is returned.
  */
 
 int register_sound_dsp(const struct file_operations *fops, int dev)
diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c
index 4dd60d8a4889..a1a24b979ed2 100644
--- a/sound/spi/at73c213.c
+++ b/sound/spi/at73c213.c
@@ -1075,10 +1075,11 @@ out:
 	return 0;
 }
 
-#ifdef CONFIG_PM
-static int snd_at73c213_suspend(struct spi_device *spi, pm_message_t msg)
+#ifdef CONFIG_PM_SLEEP
+
+static int snd_at73c213_suspend(struct device *dev)
 {
-	struct snd_card *card = dev_get_drvdata(&spi->dev);
+	struct snd_card *card = dev_get_drvdata(dev);
 	struct snd_at73c213 *chip = card->private_data;
 
 	ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS));
@@ -1087,9 +1088,9 @@ static int snd_at73c213_suspend(struct spi_device *spi, pm_message_t msg)
 	return 0;
 }
 
-static int snd_at73c213_resume(struct spi_device *spi)
+static int snd_at73c213_resume(struct device *dev)
 {
-	struct snd_card *card = dev_get_drvdata(&spi->dev);
+	struct snd_card *card = dev_get_drvdata(dev);
 	struct snd_at73c213 *chip = card->private_data;
 
 	clk_enable(chip->board->dac_clk);
@@ -1097,18 +1098,21 @@ static int snd_at73c213_resume(struct spi_device *spi)
 
 	return 0;
 }
+
+static SIMPLE_DEV_PM_OPS(at73c213_pm_ops, snd_at73c213_suspend,
+		snd_at73c213_resume);
+#define AT73C213_PM_OPS (&at73c213_pm_ops)
+
 #else
-#define snd_at73c213_suspend NULL
-#define snd_at73c213_resume NULL
+#define AT73C213_PM_OPS NULL
 #endif
 
 static struct spi_driver at73c213_driver = {
 	.driver		= {
 		.name	= "at73c213",
+		.pm	= AT73C213_PM_OPS,
 	},
 	.probe		= snd_at73c213_probe,
-	.suspend	= snd_at73c213_suspend,
-	.resume		= snd_at73c213_resume,
 	.remove		= snd_at73c213_remove,
 };
 
diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c
index e2ca12fe92e9..40dd50a80f55 100644
--- a/sound/usb/6fire/pcm.c
+++ b/sound/usb/6fire/pcm.c
@@ -575,7 +575,6 @@ static void usb6fire_pcm_init_urb(struct pcm_urb *urb,
 	urb->instance.pipe = in ? usb_rcvisocpipe(chip->dev, ep)
 			: usb_sndisocpipe(chip->dev, ep);
 	urb->instance.interval = 1;
-	urb->instance.transfer_flags = URB_ISO_ASAP;
 	urb->instance.complete = handler;
 	urb->instance.context = urb;
 	urb->instance.number_of_packets = PCM_N_PACKETS_PER_URB;
diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c
index fde9a7a29cb6..c1916184e2e1 100644
--- a/sound/usb/caiaq/audio.c
+++ b/sound/usb/caiaq/audio.c
@@ -16,6 +16,7 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */
 
+#include <linux/device.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/init.h>
@@ -39,8 +40,8 @@
 #define ENDPOINT_CAPTURE	2
 #define ENDPOINT_PLAYBACK	6
 
-#define MAKE_CHECKBYTE(dev,stream,i) \
-	(stream << 1) | (~(i / (dev->n_streams * BYTES_PER_SAMPLE_USB)) & 1)
+#define MAKE_CHECKBYTE(cdev,stream,i) \
+	(stream << 1) | (~(i / (cdev->n_streams * BYTES_PER_SAMPLE_USB)) & 1)
 
 static struct snd_pcm_hardware snd_usb_caiaq_pcm_hardware = {
 	.info 		= (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
@@ -60,32 +61,32 @@ static struct snd_pcm_hardware snd_usb_caiaq_pcm_hardware = {
 };
 
 static void
-activate_substream(struct snd_usb_caiaqdev *dev,
+activate_substream(struct snd_usb_caiaqdev *cdev,
 	           struct snd_pcm_substream *sub)
 {
-	spin_lock(&dev->spinlock);
+	spin_lock(&cdev->spinlock);
 
 	if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		dev->sub_playback[sub->number] = sub;
+		cdev->sub_playback[sub->number] = sub;
 	else
-		dev->sub_capture[sub->number] = sub;
+		cdev->sub_capture[sub->number] = sub;
 
-	spin_unlock(&dev->spinlock);
+	spin_unlock(&cdev->spinlock);
 }
 
 static void
-deactivate_substream(struct snd_usb_caiaqdev *dev,
+deactivate_substream(struct snd_usb_caiaqdev *cdev,
 		     struct snd_pcm_substream *sub)
 {
 	unsigned long flags;
-	spin_lock_irqsave(&dev->spinlock, flags);
+	spin_lock_irqsave(&cdev->spinlock, flags);
 
 	if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		dev->sub_playback[sub->number] = NULL;
+		cdev->sub_playback[sub->number] = NULL;
 	else
-		dev->sub_capture[sub->number] = NULL;
+		cdev->sub_capture[sub->number] = NULL;
 
-	spin_unlock_irqrestore(&dev->spinlock, flags);
+	spin_unlock_irqrestore(&cdev->spinlock, flags);
 }
 
 static int
@@ -98,28 +99,30 @@ all_substreams_zero(struct snd_pcm_substream **subs)
 	return 1;
 }
 
-static int stream_start(struct snd_usb_caiaqdev *dev)
+static int stream_start(struct snd_usb_caiaqdev *cdev)
 {
 	int i, ret;
+	struct device *dev = caiaqdev_to_dev(cdev);
 
-	debug("%s(%p)\n", __func__, dev);
+	dev_dbg(dev, "%s(%p)\n", __func__, cdev);
 
-	if (dev->streaming)
+	if (cdev->streaming)
 		return -EINVAL;
 
-	memset(dev->sub_playback, 0, sizeof(dev->sub_playback));
-	memset(dev->sub_capture, 0, sizeof(dev->sub_capture));
-	dev->input_panic = 0;
-	dev->output_panic = 0;
-	dev->first_packet = 4;
-	dev->streaming = 1;
-	dev->warned = 0;
+	memset(cdev->sub_playback, 0, sizeof(cdev->sub_playback));
+	memset(cdev->sub_capture, 0, sizeof(cdev->sub_capture));
+	cdev->input_panic = 0;
+	cdev->output_panic = 0;
+	cdev->first_packet = 4;
+	cdev->streaming = 1;
+	cdev->warned = 0;
 
 	for (i = 0; i < N_URBS; i++) {
-		ret = usb_submit_urb(dev->data_urbs_in[i], GFP_ATOMIC);
+		ret = usb_submit_urb(cdev->data_urbs_in[i], GFP_ATOMIC);
 		if (ret) {
-			log("unable to trigger read #%d! (ret %d)\n", i, ret);
-			dev->streaming = 0;
+			dev_err(dev, "unable to trigger read #%d! (ret %d)\n",
+				i, ret);
+			cdev->streaming = 0;
 			return -EPIPE;
 		}
 	}
@@ -127,46 +130,51 @@ static int stream_start(struct snd_usb_caiaqdev *dev)
 	return 0;
 }
 
-static void stream_stop(struct snd_usb_caiaqdev *dev)
+static void stream_stop(struct snd_usb_caiaqdev *cdev)
 {
 	int i;
+	struct device *dev = caiaqdev_to_dev(cdev);
 
-	debug("%s(%p)\n", __func__, dev);
-	if (!dev->streaming)
+	dev_dbg(dev, "%s(%p)\n", __func__, cdev);
+	if (!cdev->streaming)
 		return;
 
-	dev->streaming = 0;
+	cdev->streaming = 0;
 
 	for (i = 0; i < N_URBS; i++) {
-		usb_kill_urb(dev->data_urbs_in[i]);
+		usb_kill_urb(cdev->data_urbs_in[i]);
 
-		if (test_bit(i, &dev->outurb_active_mask))
-			usb_kill_urb(dev->data_urbs_out[i]);
+		if (test_bit(i, &cdev->outurb_active_mask))
+			usb_kill_urb(cdev->data_urbs_out[i]);
 	}
 
-	dev->outurb_active_mask = 0;
+	cdev->outurb_active_mask = 0;
 }
 
 static int snd_usb_caiaq_substream_open(struct snd_pcm_substream *substream)
 {
-	struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream);
-	debug("%s(%p)\n", __func__, substream);
-	substream->runtime->hw = dev->pcm_info;
+	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(substream);
+	struct device *dev = caiaqdev_to_dev(cdev);
+
+	dev_dbg(dev, "%s(%p)\n", __func__, substream);
+	substream->runtime->hw = cdev->pcm_info;
 	snd_pcm_limit_hw_rates(substream->runtime);
+
 	return 0;
 }
 
 static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream)
 {
-	struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream);
+	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(substream);
+	struct device *dev = caiaqdev_to_dev(cdev);
 
-	debug("%s(%p)\n", __func__, substream);
-	if (all_substreams_zero(dev->sub_playback) &&
-	    all_substreams_zero(dev->sub_capture)) {
+	dev_dbg(dev, "%s(%p)\n", __func__, substream);
+	if (all_substreams_zero(cdev->sub_playback) &&
+	    all_substreams_zero(cdev->sub_capture)) {
 		/* when the last client has stopped streaming,
 		 * all sample rates are allowed again */
-		stream_stop(dev);
-		dev->pcm_info.rates = dev->samplerates;
+		stream_stop(cdev);
+		cdev->pcm_info.rates = cdev->samplerates;
 	}
 
 	return 0;
@@ -175,15 +183,13 @@ static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream)
 static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub,
 				       struct snd_pcm_hw_params *hw_params)
 {
-	debug("%s(%p)\n", __func__, sub);
 	return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params));
 }
 
 static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub)
 {
-	struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub);
-	debug("%s(%p)\n", __func__, sub);
-	deactivate_substream(dev, sub);
+	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(sub);
+	deactivate_substream(cdev, sub);
 	return snd_pcm_lib_free_pages(sub);
 }
 
@@ -199,15 +205,16 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
 {
 	int bytes_per_sample, bpp, ret, i;
 	int index = substream->number;
-	struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream);
+	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct device *dev = caiaqdev_to_dev(cdev);
 
-	debug("%s(%p)\n", __func__, substream);
+	dev_dbg(dev, "%s(%p)\n", __func__, substream);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		int out_pos;
 
-		switch (dev->spec.data_alignment) {
+		switch (cdev->spec.data_alignment) {
 		case 0:
 		case 2:
 			out_pos = BYTES_PER_SAMPLE + 1;
@@ -218,12 +225,12 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
 			break;
 		}
 
-		dev->period_out_count[index] = out_pos;
-		dev->audio_out_buf_pos[index] = out_pos;
+		cdev->period_out_count[index] = out_pos;
+		cdev->audio_out_buf_pos[index] = out_pos;
 	} else {
 		int in_pos;
 
-		switch (dev->spec.data_alignment) {
+		switch (cdev->spec.data_alignment) {
 		case 0:
 			in_pos = BYTES_PER_SAMPLE + 2;
 			break;
@@ -236,44 +243,44 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
 			break;
 		}
 
-		dev->period_in_count[index] = in_pos;
-		dev->audio_in_buf_pos[index] = in_pos;
+		cdev->period_in_count[index] = in_pos;
+		cdev->audio_in_buf_pos[index] = in_pos;
 	}
 
-	if (dev->streaming)
+	if (cdev->streaming)
 		return 0;
 
 	/* the first client that opens a stream defines the sample rate
 	 * setting for all subsequent calls, until the last client closed. */
 	for (i=0; i < ARRAY_SIZE(rates); i++)
 		if (runtime->rate == rates[i])
-			dev->pcm_info.rates = 1 << i;
+			cdev->pcm_info.rates = 1 << i;
 
 	snd_pcm_limit_hw_rates(runtime);
 
 	bytes_per_sample = BYTES_PER_SAMPLE;
-	if (dev->spec.data_alignment >= 2)
+	if (cdev->spec.data_alignment >= 2)
 		bytes_per_sample++;
 
 	bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE)
-		* bytes_per_sample * CHANNELS_PER_STREAM * dev->n_streams;
+		* bytes_per_sample * CHANNELS_PER_STREAM * cdev->n_streams;
 
 	if (bpp > MAX_ENDPOINT_SIZE)
 		bpp = MAX_ENDPOINT_SIZE;
 
-	ret = snd_usb_caiaq_set_audio_params(dev, runtime->rate,
+	ret = snd_usb_caiaq_set_audio_params(cdev, runtime->rate,
 					     runtime->sample_bits, bpp);
 	if (ret)
 		return ret;
 
-	ret = stream_start(dev);
+	ret = stream_start(cdev);
 	if (ret)
 		return ret;
 
-	dev->output_running = 0;
-	wait_event_timeout(dev->prepare_wait_queue, dev->output_running, HZ);
-	if (!dev->output_running) {
-		stream_stop(dev);
+	cdev->output_running = 0;
+	wait_event_timeout(cdev->prepare_wait_queue, cdev->output_running, HZ);
+	if (!cdev->output_running) {
+		stream_stop(cdev);
 		return -EPIPE;
 	}
 
@@ -282,18 +289,19 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
 
 static int snd_usb_caiaq_pcm_trigger(struct snd_pcm_substream *sub, int cmd)
 {
-	struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub);
+	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(sub);
+	struct device *dev = caiaqdev_to_dev(cdev);
 
-	debug("%s(%p) cmd %d\n", __func__, sub, cmd);
+	dev_dbg(dev, "%s(%p) cmd %d\n", __func__, sub, cmd);
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		activate_substream(dev, sub);
+		activate_substream(cdev, sub);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		deactivate_substream(dev, sub);
+		deactivate_substream(cdev, sub);
 		break;
 	default:
 		return -EINVAL;
@@ -306,25 +314,25 @@ static snd_pcm_uframes_t
 snd_usb_caiaq_pcm_pointer(struct snd_pcm_substream *sub)
 {
 	int index = sub->number;
-	struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub);
+	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(sub);
 	snd_pcm_uframes_t ptr;
 
-	spin_lock(&dev->spinlock);
+	spin_lock(&cdev->spinlock);
 
-	if (dev->input_panic || dev->output_panic) {
+	if (cdev->input_panic || cdev->output_panic) {
 		ptr = SNDRV_PCM_POS_XRUN;
 		goto unlock;
 	}
 
 	if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		ptr = bytes_to_frames(sub->runtime,
-					dev->audio_out_buf_pos[index]);
+					cdev->audio_out_buf_pos[index]);
 	else
 		ptr = bytes_to_frames(sub->runtime,
-					dev->audio_in_buf_pos[index]);
+					cdev->audio_in_buf_pos[index]);
 
 unlock:
-	spin_unlock(&dev->spinlock);
+	spin_unlock(&cdev->spinlock);
 	return ptr;
 }
 
@@ -340,21 +348,21 @@ static struct snd_pcm_ops snd_usb_caiaq_ops = {
 	.pointer =	snd_usb_caiaq_pcm_pointer
 };
 
-static void check_for_elapsed_periods(struct snd_usb_caiaqdev *dev,
+static void check_for_elapsed_periods(struct snd_usb_caiaqdev *cdev,
 				      struct snd_pcm_substream **subs)
 {
 	int stream, pb, *cnt;
 	struct snd_pcm_substream *sub;
 
-	for (stream = 0; stream < dev->n_streams; stream++) {
+	for (stream = 0; stream < cdev->n_streams; stream++) {
 		sub = subs[stream];
 		if (!sub)
 			continue;
 
 		pb = snd_pcm_lib_period_bytes(sub);
 		cnt = (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-					&dev->period_out_count[stream] :
-					&dev->period_in_count[stream];
+					&cdev->period_out_count[stream] :
+					&cdev->period_in_count[stream];
 
 		if (*cnt >= pb) {
 			snd_pcm_period_elapsed(sub);
@@ -363,7 +371,7 @@ static void check_for_elapsed_periods(struct snd_usb_caiaqdev *dev,
 	}
 }
 
-static void read_in_urb_mode0(struct snd_usb_caiaqdev *dev,
+static void read_in_urb_mode0(struct snd_usb_caiaqdev *cdev,
 			      const struct urb *urb,
 			      const struct usb_iso_packet_descriptor *iso)
 {
@@ -371,27 +379,27 @@ static void read_in_urb_mode0(struct snd_usb_caiaqdev *dev,
 	struct snd_pcm_substream *sub;
 	int stream, i;
 
-	if (all_substreams_zero(dev->sub_capture))
+	if (all_substreams_zero(cdev->sub_capture))
 		return;
 
 	for (i = 0; i < iso->actual_length;) {
-		for (stream = 0; stream < dev->n_streams; stream++, i++) {
-			sub = dev->sub_capture[stream];
+		for (stream = 0; stream < cdev->n_streams; stream++, i++) {
+			sub = cdev->sub_capture[stream];
 			if (sub) {
 				struct snd_pcm_runtime *rt = sub->runtime;
 				char *audio_buf = rt->dma_area;
 				int sz = frames_to_bytes(rt, rt->buffer_size);
-				audio_buf[dev->audio_in_buf_pos[stream]++]
+				audio_buf[cdev->audio_in_buf_pos[stream]++]
 					= usb_buf[i];
-				dev->period_in_count[stream]++;
-				if (dev->audio_in_buf_pos[stream] == sz)
-					dev->audio_in_buf_pos[stream] = 0;
+				cdev->period_in_count[stream]++;
+				if (cdev->audio_in_buf_pos[stream] == sz)
+					cdev->audio_in_buf_pos[stream] = 0;
 			}
 		}
 	}
 }
 
-static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev,
+static void read_in_urb_mode2(struct snd_usb_caiaqdev *cdev,
 			      const struct urb *urb,
 			      const struct usb_iso_packet_descriptor *iso)
 {
@@ -401,48 +409,49 @@ static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev,
 	int stream, i;
 
 	for (i = 0; i < iso->actual_length;) {
-		if (i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == 0) {
+		if (i % (cdev->n_streams * BYTES_PER_SAMPLE_USB) == 0) {
 			for (stream = 0;
-			     stream < dev->n_streams;
+			     stream < cdev->n_streams;
 			     stream++, i++) {
-				if (dev->first_packet)
+				if (cdev->first_packet)
 					continue;
 
-				check_byte = MAKE_CHECKBYTE(dev, stream, i);
+				check_byte = MAKE_CHECKBYTE(cdev, stream, i);
 
 				if ((usb_buf[i] & 0x3f) != check_byte)
-					dev->input_panic = 1;
+					cdev->input_panic = 1;
 
 				if (usb_buf[i] & 0x80)
-					dev->output_panic = 1;
+					cdev->output_panic = 1;
 			}
 		}
-		dev->first_packet = 0;
+		cdev->first_packet = 0;
 
-		for (stream = 0; stream < dev->n_streams; stream++, i++) {
-			sub = dev->sub_capture[stream];
-			if (dev->input_panic)
+		for (stream = 0; stream < cdev->n_streams; stream++, i++) {
+			sub = cdev->sub_capture[stream];
+			if (cdev->input_panic)
 				usb_buf[i] = 0;
 
 			if (sub) {
 				struct snd_pcm_runtime *rt = sub->runtime;
 				char *audio_buf = rt->dma_area;
 				int sz = frames_to_bytes(rt, rt->buffer_size);
-				audio_buf[dev->audio_in_buf_pos[stream]++] =
+				audio_buf[cdev->audio_in_buf_pos[stream]++] =
 					usb_buf[i];
-				dev->period_in_count[stream]++;
-				if (dev->audio_in_buf_pos[stream] == sz)
-					dev->audio_in_buf_pos[stream] = 0;
+				cdev->period_in_count[stream]++;
+				if (cdev->audio_in_buf_pos[stream] == sz)
+					cdev->audio_in_buf_pos[stream] = 0;
 			}
 		}
 	}
 }
 
-static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev,
+static void read_in_urb_mode3(struct snd_usb_caiaqdev *cdev,
 			      const struct urb *urb,
 			      const struct usb_iso_packet_descriptor *iso)
 {
 	unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
+	struct device *dev = caiaqdev_to_dev(cdev);
 	int stream, i;
 
 	/* paranoia check */
@@ -450,12 +459,12 @@ static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev,
 		return;
 
 	for (i = 0; i < iso->actual_length;) {
-		for (stream = 0; stream < dev->n_streams; stream++) {
-			struct snd_pcm_substream *sub = dev->sub_capture[stream];
+		for (stream = 0; stream < cdev->n_streams; stream++) {
+			struct snd_pcm_substream *sub = cdev->sub_capture[stream];
 			char *audio_buf = NULL;
 			int c, n, sz = 0;
 
-			if (sub && !dev->input_panic) {
+			if (sub && !cdev->input_panic) {
 				struct snd_pcm_runtime *rt = sub->runtime;
 				audio_buf = rt->dma_area;
 				sz = frames_to_bytes(rt, rt->buffer_size);
@@ -465,23 +474,23 @@ static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev,
 				/* 3 audio data bytes, followed by 1 check byte */
 				if (audio_buf) {
 					for (n = 0; n < BYTES_PER_SAMPLE; n++) {
-						audio_buf[dev->audio_in_buf_pos[stream]++] = usb_buf[i+n];
+						audio_buf[cdev->audio_in_buf_pos[stream]++] = usb_buf[i+n];
 
-						if (dev->audio_in_buf_pos[stream] == sz)
-							dev->audio_in_buf_pos[stream] = 0;
+						if (cdev->audio_in_buf_pos[stream] == sz)
+							cdev->audio_in_buf_pos[stream] = 0;
 					}
 
-					dev->period_in_count[stream] += BYTES_PER_SAMPLE;
+					cdev->period_in_count[stream] += BYTES_PER_SAMPLE;
 				}
 
 				i += BYTES_PER_SAMPLE;
 
 				if (usb_buf[i] != ((stream << 1) | c) &&
-				    !dev->first_packet) {
-					if (!dev->input_panic)
-						printk(" EXPECTED: %02x got %02x, c %d, stream %d, i %d\n",
-							((stream << 1) | c), usb_buf[i], c, stream, i);
-					dev->input_panic = 1;
+				    !cdev->first_packet) {
+					if (!cdev->input_panic)
+						dev_warn(dev, " EXPECTED: %02x got %02x, c %d, stream %d, i %d\n",
+							 ((stream << 1) | c), usb_buf[i], c, stream, i);
+					cdev->input_panic = 1;
 				}
 
 				i++;
@@ -489,41 +498,43 @@ static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev,
 		}
 	}
 
-	if (dev->first_packet > 0)
-		dev->first_packet--;
+	if (cdev->first_packet > 0)
+		cdev->first_packet--;
 }
 
-static void read_in_urb(struct snd_usb_caiaqdev *dev,
+static void read_in_urb(struct snd_usb_caiaqdev *cdev,
 			const struct urb *urb,
 			const struct usb_iso_packet_descriptor *iso)
 {
-	if (!dev->streaming)
+	struct device *dev = caiaqdev_to_dev(cdev);
+
+	if (!cdev->streaming)
 		return;
 
-	if (iso->actual_length < dev->bpp)
+	if (iso->actual_length < cdev->bpp)
 		return;
 
-	switch (dev->spec.data_alignment) {
+	switch (cdev->spec.data_alignment) {
 	case 0:
-		read_in_urb_mode0(dev, urb, iso);
+		read_in_urb_mode0(cdev, urb, iso);
 		break;
 	case 2:
-		read_in_urb_mode2(dev, urb, iso);
+		read_in_urb_mode2(cdev, urb, iso);
 		break;
 	case 3:
-		read_in_urb_mode3(dev, urb, iso);
+		read_in_urb_mode3(cdev, urb, iso);
 		break;
 	}
 
-	if ((dev->input_panic || dev->output_panic) && !dev->warned) {
-		debug("streaming error detected %s %s\n",
-				dev->input_panic ? "(input)" : "",
-				dev->output_panic ? "(output)" : "");
-		dev->warned = 1;
+	if ((cdev->input_panic || cdev->output_panic) && !cdev->warned) {
+		dev_warn(dev, "streaming error detected %s %s\n",
+				cdev->input_panic ? "(input)" : "",
+				cdev->output_panic ? "(output)" : "");
+		cdev->warned = 1;
 	}
 }
 
-static void fill_out_urb_mode_0(struct snd_usb_caiaqdev *dev,
+static void fill_out_urb_mode_0(struct snd_usb_caiaqdev *cdev,
 				struct urb *urb,
 				const struct usb_iso_packet_descriptor *iso)
 {
@@ -532,32 +543,32 @@ static void fill_out_urb_mode_0(struct snd_usb_caiaqdev *dev,
 	int stream, i;
 
 	for (i = 0; i < iso->length;) {
-		for (stream = 0; stream < dev->n_streams; stream++, i++) {
-			sub = dev->sub_playback[stream];
+		for (stream = 0; stream < cdev->n_streams; stream++, i++) {
+			sub = cdev->sub_playback[stream];
 			if (sub) {
 				struct snd_pcm_runtime *rt = sub->runtime;
 				char *audio_buf = rt->dma_area;
 				int sz = frames_to_bytes(rt, rt->buffer_size);
 				usb_buf[i] =
-					audio_buf[dev->audio_out_buf_pos[stream]];
-				dev->period_out_count[stream]++;
-				dev->audio_out_buf_pos[stream]++;
-				if (dev->audio_out_buf_pos[stream] == sz)
-					dev->audio_out_buf_pos[stream] = 0;
+					audio_buf[cdev->audio_out_buf_pos[stream]];
+				cdev->period_out_count[stream]++;
+				cdev->audio_out_buf_pos[stream]++;
+				if (cdev->audio_out_buf_pos[stream] == sz)
+					cdev->audio_out_buf_pos[stream] = 0;
 			} else
 				usb_buf[i] = 0;
 		}
 
 		/* fill in the check bytes */
-		if (dev->spec.data_alignment == 2 &&
-		    i % (dev->n_streams * BYTES_PER_SAMPLE_USB) ==
-		        (dev->n_streams * CHANNELS_PER_STREAM))
-			for (stream = 0; stream < dev->n_streams; stream++, i++)
-				usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i);
+		if (cdev->spec.data_alignment == 2 &&
+		    i % (cdev->n_streams * BYTES_PER_SAMPLE_USB) ==
+		        (cdev->n_streams * CHANNELS_PER_STREAM))
+			for (stream = 0; stream < cdev->n_streams; stream++, i++)
+				usb_buf[i] = MAKE_CHECKBYTE(cdev, stream, i);
 	}
 }
 
-static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev,
+static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *cdev,
 				struct urb *urb,
 				const struct usb_iso_packet_descriptor *iso)
 {
@@ -565,8 +576,8 @@ static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev,
 	int stream, i;
 
 	for (i = 0; i < iso->length;) {
-		for (stream = 0; stream < dev->n_streams; stream++) {
-			struct snd_pcm_substream *sub = dev->sub_playback[stream];
+		for (stream = 0; stream < cdev->n_streams; stream++) {
+			struct snd_pcm_substream *sub = cdev->sub_playback[stream];
 			char *audio_buf = NULL;
 			int c, n, sz = 0;
 
@@ -579,17 +590,17 @@ static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev,
 			for (c = 0; c < CHANNELS_PER_STREAM; c++) {
 				for (n = 0; n < BYTES_PER_SAMPLE; n++) {
 					if (audio_buf) {
-						usb_buf[i+n] = audio_buf[dev->audio_out_buf_pos[stream]++];
+						usb_buf[i+n] = audio_buf[cdev->audio_out_buf_pos[stream]++];
 
-						if (dev->audio_out_buf_pos[stream] == sz)
-							dev->audio_out_buf_pos[stream] = 0;
+						if (cdev->audio_out_buf_pos[stream] == sz)
+							cdev->audio_out_buf_pos[stream] = 0;
 					} else {
 						usb_buf[i+n] = 0;
 					}
 				}
 
 				if (audio_buf)
-					dev->period_out_count[stream] += BYTES_PER_SAMPLE;
+					cdev->period_out_count[stream] += BYTES_PER_SAMPLE;
 
 				i += BYTES_PER_SAMPLE;
 
@@ -600,17 +611,17 @@ static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev,
 	}
 }
 
-static inline void fill_out_urb(struct snd_usb_caiaqdev *dev,
+static inline void fill_out_urb(struct snd_usb_caiaqdev *cdev,
 				struct urb *urb,
 				const struct usb_iso_packet_descriptor *iso)
 {
-	switch (dev->spec.data_alignment) {
+	switch (cdev->spec.data_alignment) {
 	case 0:
 	case 2:
-		fill_out_urb_mode_0(dev, urb, iso);
+		fill_out_urb_mode_0(cdev, urb, iso);
 		break;
 	case 3:
-		fill_out_urb_mode_3(dev, urb, iso);
+		fill_out_urb_mode_3(cdev, urb, iso);
 		break;
 	}
 }
@@ -618,7 +629,8 @@ static inline void fill_out_urb(struct snd_usb_caiaqdev *dev,
 static void read_completed(struct urb *urb)
 {
 	struct snd_usb_caiaq_cb_info *info = urb->context;
-	struct snd_usb_caiaqdev *dev;
+	struct snd_usb_caiaqdev *cdev;
+	struct device *dev;
 	struct urb *out = NULL;
 	int i, frame, len, send_it = 0, outframe = 0;
 	size_t offset = 0;
@@ -626,20 +638,21 @@ static void read_completed(struct urb *urb)
 	if (urb->status || !info)
 		return;
 
-	dev = info->dev;
+	cdev = info->cdev;
+	dev = caiaqdev_to_dev(cdev);
 
-	if (!dev->streaming)
+	if (!cdev->streaming)
 		return;
 
 	/* find an unused output urb that is unused */
 	for (i = 0; i < N_URBS; i++)
-		if (test_and_set_bit(i, &dev->outurb_active_mask) == 0) {
-			out = dev->data_urbs_out[i];
+		if (test_and_set_bit(i, &cdev->outurb_active_mask) == 0) {
+			out = cdev->data_urbs_out[i];
 			break;
 		}
 
 	if (!out) {
-		log("Unable to find an output urb to use\n");
+		dev_err(dev, "Unable to find an output urb to use\n");
 		goto requeue;
 	}
 
@@ -656,12 +669,12 @@ static void read_completed(struct urb *urb)
 		offset += len;
 
 		if (len > 0) {
-			spin_lock(&dev->spinlock);
-			fill_out_urb(dev, out, &out->iso_frame_desc[outframe]);
-			read_in_urb(dev, urb, &urb->iso_frame_desc[frame]);
-			spin_unlock(&dev->spinlock);
-			check_for_elapsed_periods(dev, dev->sub_playback);
-			check_for_elapsed_periods(dev, dev->sub_capture);
+			spin_lock(&cdev->spinlock);
+			fill_out_urb(cdev, out, &out->iso_frame_desc[outframe]);
+			read_in_urb(cdev, urb, &urb->iso_frame_desc[frame]);
+			spin_unlock(&cdev->spinlock);
+			check_for_elapsed_periods(cdev, cdev->sub_playback);
+			check_for_elapsed_periods(cdev, cdev->sub_capture);
 			send_it = 1;
 		}
 
@@ -670,11 +683,10 @@ static void read_completed(struct urb *urb)
 
 	if (send_it) {
 		out->number_of_packets = outframe;
-		out->transfer_flags = URB_ISO_ASAP;
 		usb_submit_urb(out, GFP_ATOMIC);
 	} else {
 		struct snd_usb_caiaq_cb_info *oinfo = out->context;
-		clear_bit(oinfo->index, &dev->outurb_active_mask);
+		clear_bit(oinfo->index, &cdev->outurb_active_mask);
 	}
 
 requeue:
@@ -686,28 +698,28 @@ requeue:
 	}
 
 	urb->number_of_packets = FRAMES_PER_URB;
-	urb->transfer_flags = URB_ISO_ASAP;
 	usb_submit_urb(urb, GFP_ATOMIC);
 }
 
 static void write_completed(struct urb *urb)
 {
 	struct snd_usb_caiaq_cb_info *info = urb->context;
-	struct snd_usb_caiaqdev *dev = info->dev;
+	struct snd_usb_caiaqdev *cdev = info->cdev;
 
-	if (!dev->output_running) {
-		dev->output_running = 1;
-		wake_up(&dev->prepare_wait_queue);
+	if (!cdev->output_running) {
+		cdev->output_running = 1;
+		wake_up(&cdev->prepare_wait_queue);
 	}
 
-	clear_bit(info->index, &dev->outurb_active_mask);
+	clear_bit(info->index, &cdev->outurb_active_mask);
 }
 
-static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret)
+static struct urb **alloc_urbs(struct snd_usb_caiaqdev *cdev, int dir, int *ret)
 {
 	int i, frame;
 	struct urb **urbs;
-	struct usb_device *usb_dev = dev->chip.dev;
+	struct usb_device *usb_dev = cdev->chip.dev;
+	struct device *dev = caiaqdev_to_dev(cdev);
 	unsigned int pipe;
 
 	pipe = (dir == SNDRV_PCM_STREAM_PLAYBACK) ?
@@ -716,7 +728,7 @@ static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret)
 
 	urbs = kmalloc(N_URBS * sizeof(*urbs), GFP_KERNEL);
 	if (!urbs) {
-		log("unable to kmalloc() urbs, OOM!?\n");
+		dev_err(dev, "unable to kmalloc() urbs, OOM!?\n");
 		*ret = -ENOMEM;
 		return NULL;
 	}
@@ -724,7 +736,7 @@ static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret)
 	for (i = 0; i < N_URBS; i++) {
 		urbs[i] = usb_alloc_urb(FRAMES_PER_URB, GFP_KERNEL);
 		if (!urbs[i]) {
-			log("unable to usb_alloc_urb(), OOM!?\n");
+			dev_err(dev, "unable to usb_alloc_urb(), OOM!?\n");
 			*ret = -ENOMEM;
 			return urbs;
 		}
@@ -732,7 +744,7 @@ static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret)
 		urbs[i]->transfer_buffer =
 			kmalloc(FRAMES_PER_URB * BYTES_PER_FRAME, GFP_KERNEL);
 		if (!urbs[i]->transfer_buffer) {
-			log("unable to kmalloc() transfer buffer, OOM!?\n");
+			dev_err(dev, "unable to kmalloc() transfer buffer, OOM!?\n");
 			*ret = -ENOMEM;
 			return urbs;
 		}
@@ -749,9 +761,8 @@ static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret)
 		urbs[i]->pipe = pipe;
 		urbs[i]->transfer_buffer_length = FRAMES_PER_URB
 						* BYTES_PER_FRAME;
-		urbs[i]->context = &dev->data_cb_info[i];
+		urbs[i]->context = &cdev->data_cb_info[i];
 		urbs[i]->interval = 1;
-		urbs[i]->transfer_flags = URB_ISO_ASAP;
 		urbs[i]->number_of_packets = FRAMES_PER_URB;
 		urbs[i]->complete = (dir == SNDRV_PCM_STREAM_CAPTURE) ?
 					read_completed : write_completed;
@@ -780,110 +791,113 @@ static void free_urbs(struct urb **urbs)
 	kfree(urbs);
 }
 
-int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev)
+int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev)
 {
 	int i, ret;
+	struct device *dev = caiaqdev_to_dev(cdev);
 
-	dev->n_audio_in  = max(dev->spec.num_analog_audio_in,
-			       dev->spec.num_digital_audio_in) /
+	cdev->n_audio_in  = max(cdev->spec.num_analog_audio_in,
+			       cdev->spec.num_digital_audio_in) /
 				CHANNELS_PER_STREAM;
-	dev->n_audio_out = max(dev->spec.num_analog_audio_out,
-			       dev->spec.num_digital_audio_out) /
+	cdev->n_audio_out = max(cdev->spec.num_analog_audio_out,
+			       cdev->spec.num_digital_audio_out) /
 				CHANNELS_PER_STREAM;
-	dev->n_streams = max(dev->n_audio_in, dev->n_audio_out);
+	cdev->n_streams = max(cdev->n_audio_in, cdev->n_audio_out);
 
-	debug("dev->n_audio_in = %d\n", dev->n_audio_in);
-	debug("dev->n_audio_out = %d\n", dev->n_audio_out);
-	debug("dev->n_streams = %d\n", dev->n_streams);
+	dev_dbg(dev, "cdev->n_audio_in = %d\n", cdev->n_audio_in);
+	dev_dbg(dev, "cdev->n_audio_out = %d\n", cdev->n_audio_out);
+	dev_dbg(dev, "cdev->n_streams = %d\n", cdev->n_streams);
 
-	if (dev->n_streams > MAX_STREAMS) {
-		log("unable to initialize device, too many streams.\n");
+	if (cdev->n_streams > MAX_STREAMS) {
+		dev_err(dev, "unable to initialize device, too many streams.\n");
 		return -EINVAL;
 	}
 
-	ret = snd_pcm_new(dev->chip.card, dev->product_name, 0,
-			dev->n_audio_out, dev->n_audio_in, &dev->pcm);
+	ret = snd_pcm_new(cdev->chip.card, cdev->product_name, 0,
+			cdev->n_audio_out, cdev->n_audio_in, &cdev->pcm);
 
 	if (ret < 0) {
-		log("snd_pcm_new() returned %d\n", ret);
+		dev_err(dev, "snd_pcm_new() returned %d\n", ret);
 		return ret;
 	}
 
-	dev->pcm->private_data = dev;
-	strlcpy(dev->pcm->name, dev->product_name, sizeof(dev->pcm->name));
+	cdev->pcm->private_data = cdev;
+	strlcpy(cdev->pcm->name, cdev->product_name, sizeof(cdev->pcm->name));
 
-	memset(dev->sub_playback, 0, sizeof(dev->sub_playback));
-	memset(dev->sub_capture, 0, sizeof(dev->sub_capture));
+	memset(cdev->sub_playback, 0, sizeof(cdev->sub_playback));
+	memset(cdev->sub_capture, 0, sizeof(cdev->sub_capture));
 
-	memcpy(&dev->pcm_info, &snd_usb_caiaq_pcm_hardware,
+	memcpy(&cdev->pcm_info, &snd_usb_caiaq_pcm_hardware,
 			sizeof(snd_usb_caiaq_pcm_hardware));
 
 	/* setup samplerates */
-	dev->samplerates = dev->pcm_info.rates;
-	switch (dev->chip.usb_id) {
+	cdev->samplerates = cdev->pcm_info.rates;
+	switch (cdev->chip.usb_id) {
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_SESSIONIO):
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_GUITARRIGMOBILE):
-		dev->samplerates |= SNDRV_PCM_RATE_192000;
+		cdev->samplerates |= SNDRV_PCM_RATE_192000;
 		/* fall thru */
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO2DJ):
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORAUDIO2):
-		dev->samplerates |= SNDRV_PCM_RATE_88200;
+		cdev->samplerates |= SNDRV_PCM_RATE_88200;
 		break;
 	}
 
-	snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK,
+	snd_pcm_set_ops(cdev->pcm, SNDRV_PCM_STREAM_PLAYBACK,
 				&snd_usb_caiaq_ops);
-	snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE,
+	snd_pcm_set_ops(cdev->pcm, SNDRV_PCM_STREAM_CAPTURE,
 				&snd_usb_caiaq_ops);
 
-	snd_pcm_lib_preallocate_pages_for_all(dev->pcm,
+	snd_pcm_lib_preallocate_pages_for_all(cdev->pcm,
 					SNDRV_DMA_TYPE_CONTINUOUS,
 					snd_dma_continuous_data(GFP_KERNEL),
 					MAX_BUFFER_SIZE, MAX_BUFFER_SIZE);
 
-	dev->data_cb_info =
+	cdev->data_cb_info =
 		kmalloc(sizeof(struct snd_usb_caiaq_cb_info) * N_URBS,
 					GFP_KERNEL);
 
-	if (!dev->data_cb_info)
+	if (!cdev->data_cb_info)
 		return -ENOMEM;
 
-	dev->outurb_active_mask = 0;
-	BUILD_BUG_ON(N_URBS > (sizeof(dev->outurb_active_mask) * 8));
+	cdev->outurb_active_mask = 0;
+	BUILD_BUG_ON(N_URBS > (sizeof(cdev->outurb_active_mask) * 8));
 
 	for (i = 0; i < N_URBS; i++) {
-		dev->data_cb_info[i].dev = dev;
-		dev->data_cb_info[i].index = i;
+		cdev->data_cb_info[i].cdev = cdev;
+		cdev->data_cb_info[i].index = i;
 	}
 
-	dev->data_urbs_in = alloc_urbs(dev, SNDRV_PCM_STREAM_CAPTURE, &ret);
+	cdev->data_urbs_in = alloc_urbs(cdev, SNDRV_PCM_STREAM_CAPTURE, &ret);
 	if (ret < 0) {
-		kfree(dev->data_cb_info);
-		free_urbs(dev->data_urbs_in);
+		kfree(cdev->data_cb_info);
+		free_urbs(cdev->data_urbs_in);
 		return ret;
 	}
 
-	dev->data_urbs_out = alloc_urbs(dev, SNDRV_PCM_STREAM_PLAYBACK, &ret);
+	cdev->data_urbs_out = alloc_urbs(cdev, SNDRV_PCM_STREAM_PLAYBACK, &ret);
 	if (ret < 0) {
-		kfree(dev->data_cb_info);
-		free_urbs(dev->data_urbs_in);
-		free_urbs(dev->data_urbs_out);
+		kfree(cdev->data_cb_info);
+		free_urbs(cdev->data_urbs_in);
+		free_urbs(cdev->data_urbs_out);
 		return ret;
 	}
 
 	return 0;
 }
 
-void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *dev)
+void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev)
 {
-	debug("%s(%p)\n", __func__, dev);
-	stream_stop(dev);
-	free_urbs(dev->data_urbs_in);
-	free_urbs(dev->data_urbs_out);
-	kfree(dev->data_cb_info);
+	struct device *dev = caiaqdev_to_dev(cdev);
+
+	dev_dbg(dev, "%s(%p)\n", __func__, cdev);
+	stream_stop(cdev);
+	free_urbs(cdev->data_urbs_in);
+	free_urbs(cdev->data_urbs_out);
+	kfree(cdev->data_cb_info);
 }
 
diff --git a/sound/usb/caiaq/audio.h b/sound/usb/caiaq/audio.h
index 8ab1f8d9529e..bdf155300a8a 100644
--- a/sound/usb/caiaq/audio.h
+++ b/sound/usb/caiaq/audio.h
@@ -1,7 +1,7 @@
 #ifndef CAIAQ_AUDIO_H
 #define CAIAQ_AUDIO_H
 
-int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev);
-void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *dev);
+int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev);
+void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev);
 
 #endif /* CAIAQ_AUDIO_H */
diff --git a/sound/usb/caiaq/control.c b/sound/usb/caiaq/control.c
index adb8d03267a0..ae6b50f9ed56 100644
--- a/sound/usb/caiaq/control.c
+++ b/sound/usb/caiaq/control.c
@@ -17,6 +17,7 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
+#include <linux/device.h>
 #include <linux/init.h>
 #include <linux/usb.h>
 #include <sound/control.h>
@@ -32,7 +33,7 @@ static int control_info(struct snd_kcontrol *kcontrol,
 			struct snd_ctl_elem_info *uinfo)
 {
 	struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol);
-	struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
+	struct snd_usb_caiaqdev *cdev = caiaqdev(chip->card);
 	int pos = kcontrol->private_value;
 	int is_intval = pos & CNT_INTVAL;
 	int maxval = 63;
@@ -40,7 +41,7 @@ static int control_info(struct snd_kcontrol *kcontrol,
 	uinfo->count = 1;
 	pos &= ~CNT_INTVAL;
 
-	switch (dev->chip.usb_id) {
+	switch (cdev->chip.usb_id) {
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
 		if (pos == 0) {
@@ -78,15 +79,15 @@ static int control_get(struct snd_kcontrol *kcontrol,
 		       struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol);
-	struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
+	struct snd_usb_caiaqdev *cdev = caiaqdev(chip->card);
 	int pos = kcontrol->private_value;
 
 	if (pos & CNT_INTVAL)
 		ucontrol->value.integer.value[0]
-			= dev->control_state[pos & ~CNT_INTVAL];
+			= cdev->control_state[pos & ~CNT_INTVAL];
 	else
 		ucontrol->value.integer.value[0]
-			= !!(dev->control_state[pos / 8] & (1 << pos % 8));
+			= !!(cdev->control_state[pos / 8] & (1 << pos % 8));
 
 	return 0;
 }
@@ -95,43 +96,43 @@ static int control_put(struct snd_kcontrol *kcontrol,
 		       struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol);
-	struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
+	struct snd_usb_caiaqdev *cdev = caiaqdev(chip->card);
 	int pos = kcontrol->private_value;
 	int v = ucontrol->value.integer.value[0];
 	unsigned char cmd = EP1_CMD_WRITE_IO;
 
-	if (dev->chip.usb_id ==
+	if (cdev->chip.usb_id ==
 		USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1))
 		cmd = EP1_CMD_DIMM_LEDS;
 
 	if (pos & CNT_INTVAL) {
 		int i = pos & ~CNT_INTVAL;
 
-		dev->control_state[i] = v;
+		cdev->control_state[i] = v;
 
-		if (dev->chip.usb_id ==
+		if (cdev->chip.usb_id ==
 			USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4)) {
 			int actual_len;
 
-			dev->ep8_out_buf[0] = i;
-			dev->ep8_out_buf[1] = v;
+			cdev->ep8_out_buf[0] = i;
+			cdev->ep8_out_buf[1] = v;
 
-			usb_bulk_msg(dev->chip.dev,
-				     usb_sndbulkpipe(dev->chip.dev, 8),
-				     dev->ep8_out_buf, sizeof(dev->ep8_out_buf),
+			usb_bulk_msg(cdev->chip.dev,
+				     usb_sndbulkpipe(cdev->chip.dev, 8),
+				     cdev->ep8_out_buf, sizeof(cdev->ep8_out_buf),
 				     &actual_len, 200);
 		} else {
-			snd_usb_caiaq_send_command(dev, cmd,
-					dev->control_state, sizeof(dev->control_state));
+			snd_usb_caiaq_send_command(cdev, cmd,
+					cdev->control_state, sizeof(cdev->control_state));
 		}
 	} else {
 		if (v)
-			dev->control_state[pos / 8] |= 1 << (pos % 8);
+			cdev->control_state[pos / 8] |= 1 << (pos % 8);
 		else
-			dev->control_state[pos / 8] &= ~(1 << (pos % 8));
+			cdev->control_state[pos / 8] &= ~(1 << (pos % 8));
 
-		snd_usb_caiaq_send_command(dev, cmd,
-				dev->control_state, sizeof(dev->control_state));
+		snd_usb_caiaq_send_command(cdev, cmd,
+				cdev->control_state, sizeof(cdev->control_state));
 	}
 
 	return 1;
@@ -490,7 +491,7 @@ static struct caiaq_controller kontrols4_controller[] = {
 };
 
 static int add_controls(struct caiaq_controller *c, int num,
-			struct snd_usb_caiaqdev *dev)
+			struct snd_usb_caiaqdev *cdev)
 {
 	int i, ret;
 	struct snd_kcontrol *kc;
@@ -498,8 +499,8 @@ static int add_controls(struct caiaq_controller *c, int num,
 	for (i = 0; i < num; i++, c++) {
 		kcontrol_template.name = c->name;
 		kcontrol_template.private_value = c->index;
-		kc = snd_ctl_new1(&kcontrol_template, dev);
-		ret = snd_ctl_add(dev->chip.card, kc);
+		kc = snd_ctl_new1(&kcontrol_template, cdev);
+		ret = snd_ctl_add(cdev->chip.card, kc);
 		if (ret < 0)
 			return ret;
 	}
@@ -507,50 +508,50 @@ static int add_controls(struct caiaq_controller *c, int num,
 	return 0;
 }
 
-int snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev)
+int snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *cdev)
 {
 	int ret = 0;
 
-	switch (dev->chip.usb_id) {
+	switch (cdev->chip.usb_id) {
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
 		ret = add_controls(ak1_controller,
-			ARRAY_SIZE(ak1_controller), dev);
+			ARRAY_SIZE(ak1_controller), cdev);
 		break;
 
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
 		ret = add_controls(rk2_controller,
-			ARRAY_SIZE(rk2_controller), dev);
+			ARRAY_SIZE(rk2_controller), cdev);
 		break;
 
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
 		ret = add_controls(rk3_controller,
-			ARRAY_SIZE(rk3_controller), dev);
+			ARRAY_SIZE(rk3_controller), cdev);
 		break;
 
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
 		ret = add_controls(kore_controller,
-			ARRAY_SIZE(kore_controller), dev);
+			ARRAY_SIZE(kore_controller), cdev);
 		break;
 
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
 		ret = add_controls(a8dj_controller,
-			ARRAY_SIZE(a8dj_controller), dev);
+			ARRAY_SIZE(a8dj_controller), cdev);
 		break;
 
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
 		ret = add_controls(a4dj_controller,
-			ARRAY_SIZE(a4dj_controller), dev);
+			ARRAY_SIZE(a4dj_controller), cdev);
 		break;
 
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
 		ret = add_controls(kontrolx1_controller,
-			ARRAY_SIZE(kontrolx1_controller), dev);
+			ARRAY_SIZE(kontrolx1_controller), cdev);
 		break;
 
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
 		ret = add_controls(kontrols4_controller,
-			ARRAY_SIZE(kontrols4_controller), dev);
+			ARRAY_SIZE(kontrols4_controller), cdev);
 		break;
 	}
 
diff --git a/sound/usb/caiaq/control.h b/sound/usb/caiaq/control.h
index 2e7ab1aa4fb3..501c4883aef6 100644
--- a/sound/usb/caiaq/control.h
+++ b/sound/usb/caiaq/control.h
@@ -1,6 +1,6 @@
 #ifndef CAIAQ_CONTROL_H
 #define CAIAQ_CONTROL_H
 
-int snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev);
+int snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *cdev);
 
 #endif /* CAIAQ_CONTROL_H */
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index e4d6dbb0342d..48b63ccc78c7 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -20,6 +20,7 @@
 */
 
 #include <linux/moduleparam.h>
+#include <linux/device.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -158,67 +159,68 @@ static struct usb_device_id snd_usb_id_table[] = {
 static void usb_ep1_command_reply_dispatch (struct urb* urb)
 {
 	int ret;
-	struct snd_usb_caiaqdev *dev = urb->context;
+	struct device *dev = &urb->dev->dev;
+	struct snd_usb_caiaqdev *cdev = urb->context;
 	unsigned char *buf = urb->transfer_buffer;
 
-	if (urb->status || !dev) {
-		log("received EP1 urb->status = %i\n", urb->status);
+	if (urb->status || !cdev) {
+		dev_warn(dev, "received EP1 urb->status = %i\n", urb->status);
 		return;
 	}
 
 	switch(buf[0]) {
 	case EP1_CMD_GET_DEVICE_INFO:
-	 	memcpy(&dev->spec, buf+1, sizeof(struct caiaq_device_spec));
-		dev->spec.fw_version = le16_to_cpu(dev->spec.fw_version);
-		debug("device spec (firmware %d): audio: %d in, %d out, "
+	 	memcpy(&cdev->spec, buf+1, sizeof(struct caiaq_device_spec));
+		cdev->spec.fw_version = le16_to_cpu(cdev->spec.fw_version);
+		dev_dbg(dev, "device spec (firmware %d): audio: %d in, %d out, "
 			"MIDI: %d in, %d out, data alignment %d\n",
-			dev->spec.fw_version,
-			dev->spec.num_analog_audio_in,
-			dev->spec.num_analog_audio_out,
-			dev->spec.num_midi_in,
-			dev->spec.num_midi_out,
-			dev->spec.data_alignment);
-
-		dev->spec_received++;
-		wake_up(&dev->ep1_wait_queue);
+			cdev->spec.fw_version,
+			cdev->spec.num_analog_audio_in,
+			cdev->spec.num_analog_audio_out,
+			cdev->spec.num_midi_in,
+			cdev->spec.num_midi_out,
+			cdev->spec.data_alignment);
+
+		cdev->spec_received++;
+		wake_up(&cdev->ep1_wait_queue);
 		break;
 	case EP1_CMD_AUDIO_PARAMS:
-		dev->audio_parm_answer = buf[1];
-		wake_up(&dev->ep1_wait_queue);
+		cdev->audio_parm_answer = buf[1];
+		wake_up(&cdev->ep1_wait_queue);
 		break;
 	case EP1_CMD_MIDI_READ:
-		snd_usb_caiaq_midi_handle_input(dev, buf[1], buf + 3, buf[2]);
+		snd_usb_caiaq_midi_handle_input(cdev, buf[1], buf + 3, buf[2]);
 		break;
 	case EP1_CMD_READ_IO:
-		if (dev->chip.usb_id ==
+		if (cdev->chip.usb_id ==
 			USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ)) {
-			if (urb->actual_length > sizeof(dev->control_state))
-				urb->actual_length = sizeof(dev->control_state);
-			memcpy(dev->control_state, buf + 1, urb->actual_length);
-			wake_up(&dev->ep1_wait_queue);
+			if (urb->actual_length > sizeof(cdev->control_state))
+				urb->actual_length = sizeof(cdev->control_state);
+			memcpy(cdev->control_state, buf + 1, urb->actual_length);
+			wake_up(&cdev->ep1_wait_queue);
 			break;
 		}
 #ifdef CONFIG_SND_USB_CAIAQ_INPUT
 	case EP1_CMD_READ_ERP:
 	case EP1_CMD_READ_ANALOG:
-		snd_usb_caiaq_input_dispatch(dev, buf, urb->actual_length);
+		snd_usb_caiaq_input_dispatch(cdev, buf, urb->actual_length);
 #endif
 		break;
 	}
 
-	dev->ep1_in_urb.actual_length = 0;
-	ret = usb_submit_urb(&dev->ep1_in_urb, GFP_ATOMIC);
+	cdev->ep1_in_urb.actual_length = 0;
+	ret = usb_submit_urb(&cdev->ep1_in_urb, GFP_ATOMIC);
 	if (ret < 0)
-		log("unable to submit urb. OOM!?\n");
+		dev_err(dev, "unable to submit urb. OOM!?\n");
 }
 
-int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *dev,
+int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *cdev,
 			       unsigned char command,
 			       const unsigned char *buffer,
 			       int len)
 {
 	int actual_len;
-	struct usb_device *usb_dev = dev->chip.dev;
+	struct usb_device *usb_dev = cdev->chip.dev;
 
 	if (!usb_dev)
 		return -EIO;
@@ -227,18 +229,19 @@ int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *dev,
 		len = EP1_BUFSIZE - 1;
 
 	if (buffer && len > 0)
-		memcpy(dev->ep1_out_buf+1, buffer, len);
+		memcpy(cdev->ep1_out_buf+1, buffer, len);
 
-	dev->ep1_out_buf[0] = command;
+	cdev->ep1_out_buf[0] = command;
 	return usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, 1),
-			   dev->ep1_out_buf, len+1, &actual_len, 200);
+			   cdev->ep1_out_buf, len+1, &actual_len, 200);
 }
 
-int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev,
+int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *cdev,
 		   		    int rate, int depth, int bpp)
 {
 	int ret;
 	char tmp[5];
+	struct device *dev = caiaqdev_to_dev(cdev);
 
 	switch (rate) {
 	case 44100:	tmp[0] = SAMPLERATE_44100;   break;
@@ -259,49 +262,50 @@ int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev,
 	tmp[3] = bpp >> 8;
 	tmp[4] = 1; /* packets per microframe */
 
-	debug("setting audio params: %d Hz, %d bits, %d bpp\n",
+	dev_dbg(dev, "setting audio params: %d Hz, %d bits, %d bpp\n",
 		rate, depth, bpp);
 
-	dev->audio_parm_answer = -1;
-	ret = snd_usb_caiaq_send_command(dev, EP1_CMD_AUDIO_PARAMS,
+	cdev->audio_parm_answer = -1;
+	ret = snd_usb_caiaq_send_command(cdev, EP1_CMD_AUDIO_PARAMS,
 					 tmp, sizeof(tmp));
 
 	if (ret)
 		return ret;
 
-	if (!wait_event_timeout(dev->ep1_wait_queue,
-	    dev->audio_parm_answer >= 0, HZ))
+	if (!wait_event_timeout(cdev->ep1_wait_queue,
+	    cdev->audio_parm_answer >= 0, HZ))
 		return -EPIPE;
 
-	if (dev->audio_parm_answer != 1)
-		debug("unable to set the device's audio params\n");
+	if (cdev->audio_parm_answer != 1)
+		dev_dbg(dev, "unable to set the device's audio params\n");
 	else
-		dev->bpp = bpp;
+		cdev->bpp = bpp;
 
-	return dev->audio_parm_answer == 1 ? 0 : -EINVAL;
+	return cdev->audio_parm_answer == 1 ? 0 : -EINVAL;
 }
 
-int snd_usb_caiaq_set_auto_msg(struct snd_usb_caiaqdev *dev,
+int snd_usb_caiaq_set_auto_msg(struct snd_usb_caiaqdev *cdev,
 			       int digital, int analog, int erp)
 {
 	char tmp[3] = { digital, analog, erp };
-	return snd_usb_caiaq_send_command(dev, EP1_CMD_AUTO_MSG,
+	return snd_usb_caiaq_send_command(cdev, EP1_CMD_AUTO_MSG,
 					  tmp, sizeof(tmp));
 }
 
-static void setup_card(struct snd_usb_caiaqdev *dev)
+static void setup_card(struct snd_usb_caiaqdev *cdev)
 {
 	int ret;
 	char val[4];
+	struct device *dev = caiaqdev_to_dev(cdev);
 
 	/* device-specific startup specials */
-	switch (dev->chip.usb_id) {
+	switch (cdev->chip.usb_id) {
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
 		/* RigKontrol2 - display centered dash ('-') */
 		val[0] = 0x00;
 		val[1] = 0x00;
 		val[2] = 0x01;
-		snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, val, 3);
+		snd_usb_caiaq_send_command(cdev, EP1_CMD_WRITE_IO, val, 3);
 		break;
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
 		/* RigKontrol2 - display two centered dashes ('--') */
@@ -309,69 +313,69 @@ static void setup_card(struct snd_usb_caiaqdev *dev)
 		val[1] = 0x40;
 		val[2] = 0x40;
 		val[3] = 0x00;
-		snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, val, 4);
+		snd_usb_caiaq_send_command(cdev, EP1_CMD_WRITE_IO, val, 4);
 		break;
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
 		/* Audio Kontrol 1 - make USB-LED stop blinking */
 		val[0] = 0x00;
-		snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, val, 1);
+		snd_usb_caiaq_send_command(cdev, EP1_CMD_WRITE_IO, val, 1);
 		break;
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
 		/* Audio 8 DJ - trigger read of current settings */
-		dev->control_state[0] = 0xff;
-		snd_usb_caiaq_set_auto_msg(dev, 1, 0, 0);
-		snd_usb_caiaq_send_command(dev, EP1_CMD_READ_IO, NULL, 0);
+		cdev->control_state[0] = 0xff;
+		snd_usb_caiaq_set_auto_msg(cdev, 1, 0, 0);
+		snd_usb_caiaq_send_command(cdev, EP1_CMD_READ_IO, NULL, 0);
 
-		if (!wait_event_timeout(dev->ep1_wait_queue,
-					dev->control_state[0] != 0xff, HZ))
+		if (!wait_event_timeout(cdev->ep1_wait_queue,
+					cdev->control_state[0] != 0xff, HZ))
 			return;
 
 		/* fix up some defaults */
-		if ((dev->control_state[1] != 2) ||
-		    (dev->control_state[2] != 3) ||
-		    (dev->control_state[4] != 2)) {
-			dev->control_state[1] = 2;
-			dev->control_state[2] = 3;
-			dev->control_state[4] = 2;
-			snd_usb_caiaq_send_command(dev,
-				EP1_CMD_WRITE_IO, dev->control_state, 6);
+		if ((cdev->control_state[1] != 2) ||
+		    (cdev->control_state[2] != 3) ||
+		    (cdev->control_state[4] != 2)) {
+			cdev->control_state[1] = 2;
+			cdev->control_state[2] = 3;
+			cdev->control_state[4] = 2;
+			snd_usb_caiaq_send_command(cdev,
+				EP1_CMD_WRITE_IO, cdev->control_state, 6);
 		}
 
 		break;
 	}
 
-	if (dev->spec.num_analog_audio_out +
-	    dev->spec.num_analog_audio_in +
-	    dev->spec.num_digital_audio_out +
-	    dev->spec.num_digital_audio_in > 0) {
-		ret = snd_usb_caiaq_audio_init(dev);
+	if (cdev->spec.num_analog_audio_out +
+	    cdev->spec.num_analog_audio_in +
+	    cdev->spec.num_digital_audio_out +
+	    cdev->spec.num_digital_audio_in > 0) {
+		ret = snd_usb_caiaq_audio_init(cdev);
 		if (ret < 0)
-			log("Unable to set up audio system (ret=%d)\n", ret);
+			dev_err(dev, "Unable to set up audio system (ret=%d)\n", ret);
 	}
 
-	if (dev->spec.num_midi_in +
-	    dev->spec.num_midi_out > 0) {
-		ret = snd_usb_caiaq_midi_init(dev);
+	if (cdev->spec.num_midi_in +
+	    cdev->spec.num_midi_out > 0) {
+		ret = snd_usb_caiaq_midi_init(cdev);
 		if (ret < 0)
-			log("Unable to set up MIDI system (ret=%d)\n", ret);
+			dev_err(dev, "Unable to set up MIDI system (ret=%d)\n", ret);
 	}
 
 #ifdef CONFIG_SND_USB_CAIAQ_INPUT
-	ret = snd_usb_caiaq_input_init(dev);
+	ret = snd_usb_caiaq_input_init(cdev);
 	if (ret < 0)
-		log("Unable to set up input system (ret=%d)\n", ret);
+		dev_err(dev, "Unable to set up input system (ret=%d)\n", ret);
 #endif
 
 	/* finally, register the card and all its sub-instances */
-	ret = snd_card_register(dev->chip.card);
+	ret = snd_card_register(cdev->chip.card);
 	if (ret < 0) {
-		log("snd_card_register() returned %d\n", ret);
-		snd_card_free(dev->chip.card);
+		dev_err(dev, "snd_card_register() returned %d\n", ret);
+		snd_card_free(cdev->chip.card);
 	}
 
-	ret = snd_usb_caiaq_control_init(dev);
+	ret = snd_usb_caiaq_control_init(cdev);
 	if (ret < 0)
-		log("Unable to set up control system (ret=%d)\n", ret);
+		dev_err(dev, "Unable to set up control system (ret=%d)\n", ret);
 }
 
 static int create_card(struct usb_device *usb_dev,
@@ -381,7 +385,7 @@ static int create_card(struct usb_device *usb_dev,
 	int devnum;
 	int err;
 	struct snd_card *card;
-	struct snd_usb_caiaqdev *dev;
+	struct snd_usb_caiaqdev *cdev;
 
 	for (devnum = 0; devnum < SNDRV_CARDS; devnum++)
 		if (enable[devnum] && !snd_card_used[devnum])
@@ -395,65 +399,66 @@ static int create_card(struct usb_device *usb_dev,
 	if (err < 0)
 		return err;
 
-	dev = caiaqdev(card);
-	dev->chip.dev = usb_dev;
-	dev->chip.card = card;
-	dev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),
+	cdev = caiaqdev(card);
+	cdev->chip.dev = usb_dev;
+	cdev->chip.card = card;
+	cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),
 				  le16_to_cpu(usb_dev->descriptor.idProduct));
-	spin_lock_init(&dev->spinlock);
+	spin_lock_init(&cdev->spinlock);
 	snd_card_set_dev(card, &intf->dev);
 
 	*cardp = card;
 	return 0;
 }
 
-static int init_card(struct snd_usb_caiaqdev *dev)
+static int init_card(struct snd_usb_caiaqdev *cdev)
 {
 	char *c, usbpath[32];
-	struct usb_device *usb_dev = dev->chip.dev;
-	struct snd_card *card = dev->chip.card;
+	struct usb_device *usb_dev = cdev->chip.dev;
+	struct snd_card *card = cdev->chip.card;
+	struct device *dev = caiaqdev_to_dev(cdev);
 	int err, len;
 
 	if (usb_set_interface(usb_dev, 0, 1) != 0) {
-		log("can't set alt interface.\n");
+		dev_err(dev, "can't set alt interface.\n");
 		return -EIO;
 	}
 
-	usb_init_urb(&dev->ep1_in_urb);
-	usb_init_urb(&dev->midi_out_urb);
+	usb_init_urb(&cdev->ep1_in_urb);
+	usb_init_urb(&cdev->midi_out_urb);
 
-	usb_fill_bulk_urb(&dev->ep1_in_urb, usb_dev,
+	usb_fill_bulk_urb(&cdev->ep1_in_urb, usb_dev,
 			  usb_rcvbulkpipe(usb_dev, 0x1),
-			  dev->ep1_in_buf, EP1_BUFSIZE,
-			  usb_ep1_command_reply_dispatch, dev);
+			  cdev->ep1_in_buf, EP1_BUFSIZE,
+			  usb_ep1_command_reply_dispatch, cdev);
 
-	usb_fill_bulk_urb(&dev->midi_out_urb, usb_dev,
+	usb_fill_bulk_urb(&cdev->midi_out_urb, usb_dev,
 			  usb_sndbulkpipe(usb_dev, 0x1),
-			  dev->midi_out_buf, EP1_BUFSIZE,
-			  snd_usb_caiaq_midi_output_done, dev);
+			  cdev->midi_out_buf, EP1_BUFSIZE,
+			  snd_usb_caiaq_midi_output_done, cdev);
 
-	init_waitqueue_head(&dev->ep1_wait_queue);
-	init_waitqueue_head(&dev->prepare_wait_queue);
+	init_waitqueue_head(&cdev->ep1_wait_queue);
+	init_waitqueue_head(&cdev->prepare_wait_queue);
 
-	if (usb_submit_urb(&dev->ep1_in_urb, GFP_KERNEL) != 0)
+	if (usb_submit_urb(&cdev->ep1_in_urb, GFP_KERNEL) != 0)
 		return -EIO;
 
-	err = snd_usb_caiaq_send_command(dev, EP1_CMD_GET_DEVICE_INFO, NULL, 0);
+	err = snd_usb_caiaq_send_command(cdev, EP1_CMD_GET_DEVICE_INFO, NULL, 0);
 	if (err)
 		return err;
 
-	if (!wait_event_timeout(dev->ep1_wait_queue, dev->spec_received, HZ))
+	if (!wait_event_timeout(cdev->ep1_wait_queue, cdev->spec_received, HZ))
 		return -ENODEV;
 
 	usb_string(usb_dev, usb_dev->descriptor.iManufacturer,
-		   dev->vendor_name, CAIAQ_USB_STR_LEN);
+		   cdev->vendor_name, CAIAQ_USB_STR_LEN);
 
 	usb_string(usb_dev, usb_dev->descriptor.iProduct,
-		   dev->product_name, CAIAQ_USB_STR_LEN);
+		   cdev->product_name, CAIAQ_USB_STR_LEN);
 
 	strlcpy(card->driver, MODNAME, sizeof(card->driver));
-	strlcpy(card->shortname, dev->product_name, sizeof(card->shortname));
-	strlcpy(card->mixername, dev->product_name, sizeof(card->mixername));
+	strlcpy(card->shortname, cdev->product_name, sizeof(card->shortname));
+	strlcpy(card->mixername, cdev->product_name, sizeof(card->mixername));
 
 	/* if the id was not passed as module option, fill it with a shortened
 	 * version of the product string which does not contain any
@@ -473,11 +478,10 @@ static int init_card(struct snd_usb_caiaqdev *dev)
 	}
 
 	usb_make_path(usb_dev, usbpath, sizeof(usbpath));
-	snprintf(card->longname, sizeof(card->longname),
-		       "%s %s (%s)",
-		       dev->vendor_name, dev->product_name, usbpath);
+	snprintf(card->longname, sizeof(card->longname), "%s %s (%s)",
+		       cdev->vendor_name, cdev->product_name, usbpath);
 
-	setup_card(dev);
+	setup_card(cdev);
 	return 0;
 }
 
@@ -486,9 +490,9 @@ static int snd_probe(struct usb_interface *intf,
 {
 	int ret;
 	struct snd_card *card = NULL;
-	struct usb_device *device = interface_to_usbdev(intf);
+	struct usb_device *usb_dev = interface_to_usbdev(intf);
 
-	ret = create_card(device, intf, &card);
+	ret = create_card(usb_dev, intf, &card);
 
 	if (ret < 0)
 		return ret;
@@ -496,7 +500,7 @@ static int snd_probe(struct usb_interface *intf,
 	usb_set_intfdata(intf, card);
 	ret = init_card(caiaqdev(card));
 	if (ret < 0) {
-		log("unable to init card! (ret=%d)\n", ret);
+		dev_err(&usb_dev->dev, "unable to init card! (ret=%d)\n", ret);
 		snd_card_free(card);
 		return ret;
 	}
@@ -506,24 +510,25 @@ static int snd_probe(struct usb_interface *intf,
 
 static void snd_disconnect(struct usb_interface *intf)
 {
-	struct snd_usb_caiaqdev *dev;
 	struct snd_card *card = usb_get_intfdata(intf);
-
-	debug("%s(%p)\n", __func__, intf);
+	struct device *dev = intf->usb_dev;
+	struct snd_usb_caiaqdev *cdev;
 
 	if (!card)
 		return;
 
-	dev = caiaqdev(card);
+	cdev = caiaqdev(card);
+	dev_dbg(dev, "%s(%p)\n", __func__, intf);
+
 	snd_card_disconnect(card);
 
 #ifdef CONFIG_SND_USB_CAIAQ_INPUT
-	snd_usb_caiaq_input_free(dev);
+	snd_usb_caiaq_input_free(cdev);
 #endif
-	snd_usb_caiaq_audio_free(dev);
+	snd_usb_caiaq_audio_free(cdev);
 
-	usb_kill_urb(&dev->ep1_in_urb);
-	usb_kill_urb(&dev->midi_out_urb);
+	usb_kill_urb(&cdev->ep1_in_urb);
+	usb_kill_urb(&cdev->midi_out_urb);
 
 	snd_card_free(card);
 	usb_reset_device(interface_to_usbdev(intf));
@@ -539,4 +544,3 @@ static struct usb_driver snd_usb_driver = {
 };
 
 module_usb_driver(snd_usb_driver);
-
diff --git a/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h
index 562b0bff9c41..ad102fac6942 100644
--- a/sound/usb/caiaq/device.h
+++ b/sound/usb/caiaq/device.h
@@ -25,16 +25,7 @@
 #define CAIAQ_USB_STR_LEN 0xff
 #define MAX_STREAMS 32
 
-//#define	SND_USB_CAIAQ_DEBUG
-
 #define MODNAME "snd-usb-caiaq"
-#define log(x...) snd_printk(KERN_WARNING MODNAME" log: " x)
-
-#ifdef SND_USB_CAIAQ_DEBUG
-#define debug(x...) snd_printk(KERN_WARNING MODNAME " debug: " x)
-#else
-#define debug(x...) do { } while(0)
-#endif
 
 #define EP1_CMD_GET_DEVICE_INFO	0x1
 #define EP1_CMD_READ_ERP	0x2
@@ -124,15 +115,16 @@ struct snd_usb_caiaqdev {
 };
 
 struct snd_usb_caiaq_cb_info {
-	struct snd_usb_caiaqdev *dev;
+	struct snd_usb_caiaqdev *cdev;
 	int index;
 };
 
 #define caiaqdev(c) ((struct snd_usb_caiaqdev*)(c)->private_data)
+#define caiaqdev_to_dev(d)	(d->chip.card->dev)
 
-int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev, int rate, int depth, int bbp);
-int snd_usb_caiaq_set_auto_msg (struct snd_usb_caiaqdev *dev, int digital, int analog, int erp);
-int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *dev,
+int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *cdev, int rate, int depth, int bbp);
+int snd_usb_caiaq_set_auto_msg (struct snd_usb_caiaqdev *cdev, int digital, int analog, int erp);
+int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *cdev,
 			       unsigned char command,
 			       const unsigned char *buffer,
 			       int len);
diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c
index 26a121b42c3c..4b3fb91deecd 100644
--- a/sound/usb/caiaq/input.c
+++ b/sound/usb/caiaq/input.c
@@ -16,6 +16,7 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */
 
+#include <linux/device.h>
 #include <linux/gfp.h>
 #include <linux/init.h>
 #include <linux/usb.h>
@@ -199,55 +200,55 @@ static unsigned int decode_erp(unsigned char a, unsigned char b)
 #undef HIGH_PEAK
 #undef LOW_PEAK
 
-static inline void snd_caiaq_input_report_abs(struct snd_usb_caiaqdev *dev,
+static inline void snd_caiaq_input_report_abs(struct snd_usb_caiaqdev *cdev,
 					      int axis, const unsigned char *buf,
 					      int offset)
 {
-	input_report_abs(dev->input_dev, axis,
+	input_report_abs(cdev->input_dev, axis,
 			 (buf[offset * 2] << 8) | buf[offset * 2 + 1]);
 }
 
-static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev,
+static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *cdev,
 					const unsigned char *buf,
 					unsigned int len)
 {
-	struct input_dev *input_dev = dev->input_dev;
+	struct input_dev *input_dev = cdev->input_dev;
 
-	switch (dev->chip.usb_id) {
+	switch (cdev->chip.usb_id) {
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
-		snd_caiaq_input_report_abs(dev, ABS_X, buf, 2);
-		snd_caiaq_input_report_abs(dev, ABS_Y, buf, 0);
-		snd_caiaq_input_report_abs(dev, ABS_Z, buf, 1);
+		snd_caiaq_input_report_abs(cdev, ABS_X, buf, 2);
+		snd_caiaq_input_report_abs(cdev, ABS_Y, buf, 0);
+		snd_caiaq_input_report_abs(cdev, ABS_Z, buf, 1);
 		break;
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
-		snd_caiaq_input_report_abs(dev, ABS_X, buf, 0);
-		snd_caiaq_input_report_abs(dev, ABS_Y, buf, 1);
-		snd_caiaq_input_report_abs(dev, ABS_Z, buf, 2);
+		snd_caiaq_input_report_abs(cdev, ABS_X, buf, 0);
+		snd_caiaq_input_report_abs(cdev, ABS_Y, buf, 1);
+		snd_caiaq_input_report_abs(cdev, ABS_Z, buf, 2);
 		break;
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
-		snd_caiaq_input_report_abs(dev, ABS_HAT0X, buf, 4);
-		snd_caiaq_input_report_abs(dev, ABS_HAT0Y, buf, 2);
-		snd_caiaq_input_report_abs(dev, ABS_HAT1X, buf, 6);
-		snd_caiaq_input_report_abs(dev, ABS_HAT1Y, buf, 1);
-		snd_caiaq_input_report_abs(dev, ABS_HAT2X, buf, 7);
-		snd_caiaq_input_report_abs(dev, ABS_HAT2Y, buf, 0);
-		snd_caiaq_input_report_abs(dev, ABS_HAT3X, buf, 5);
-		snd_caiaq_input_report_abs(dev, ABS_HAT3Y, buf, 3);
+		snd_caiaq_input_report_abs(cdev, ABS_HAT0X, buf, 4);
+		snd_caiaq_input_report_abs(cdev, ABS_HAT0Y, buf, 2);
+		snd_caiaq_input_report_abs(cdev, ABS_HAT1X, buf, 6);
+		snd_caiaq_input_report_abs(cdev, ABS_HAT1Y, buf, 1);
+		snd_caiaq_input_report_abs(cdev, ABS_HAT2X, buf, 7);
+		snd_caiaq_input_report_abs(cdev, ABS_HAT2Y, buf, 0);
+		snd_caiaq_input_report_abs(cdev, ABS_HAT3X, buf, 5);
+		snd_caiaq_input_report_abs(cdev, ABS_HAT3Y, buf, 3);
 		break;
 	}
 
 	input_sync(input_dev);
 }
 
-static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev,
+static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *cdev,
 				     const char *buf, unsigned int len)
 {
-	struct input_dev *input_dev = dev->input_dev;
+	struct input_dev *input_dev = cdev->input_dev;
 	int i;
 
-	switch (dev->chip.usb_id) {
+	switch (cdev->chip.usb_id) {
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
 		i = decode_erp(buf[0], buf[1]);
 		input_report_abs(input_dev, ABS_X, i);
@@ -299,10 +300,10 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev,
 	}
 }
 
-static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev,
+static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *cdev,
 				    unsigned char *buf, unsigned int len)
 {
-	struct input_dev *input_dev = dev->input_dev;
+	struct input_dev *input_dev = cdev->input_dev;
 	unsigned short *keycode = input_dev->keycode;
 	int i;
 
@@ -317,17 +318,17 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev,
 		input_report_key(input_dev, keycode[i],
 				 buf[i / 8] & (1 << (i % 8)));
 
-	switch (dev->chip.usb_id) {
+	switch (cdev->chip.usb_id) {
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
-		input_report_abs(dev->input_dev, ABS_MISC, 255 - buf[4]);
+		input_report_abs(cdev->input_dev, ABS_MISC, 255 - buf[4]);
 		break;
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
 		/* rotary encoders */
-		input_report_abs(dev->input_dev, ABS_X, buf[5] & 0xf);
-		input_report_abs(dev->input_dev, ABS_Y, buf[5] >> 4);
-		input_report_abs(dev->input_dev, ABS_Z, buf[6] & 0xf);
-		input_report_abs(dev->input_dev, ABS_MISC, buf[6] >> 4);
+		input_report_abs(cdev->input_dev, ABS_X, buf[5] & 0xf);
+		input_report_abs(cdev->input_dev, ABS_Y, buf[5] >> 4);
+		input_report_abs(cdev->input_dev, ABS_Z, buf[6] & 0xf);
+		input_report_abs(cdev->input_dev, ABS_MISC, buf[6] >> 4);
 		break;
 	}
 
@@ -336,10 +337,12 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev,
 
 #define TKS4_MSGBLOCK_SIZE	16
 
-static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *dev,
+static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *cdev,
 					const unsigned char *buf,
 					unsigned int len)
 {
+	struct device *dev = caiaqdev_to_dev(cdev);
+
 	while (len) {
 		unsigned int i, block_id = (buf[0] << 8) | buf[1];
 
@@ -347,126 +350,126 @@ static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *dev,
 		case 0:
 			/* buttons */
 			for (i = 0; i < KONTROLS4_BUTTONS; i++)
-				input_report_key(dev->input_dev, KONTROLS4_BUTTON(i),
+				input_report_key(cdev->input_dev, KONTROLS4_BUTTON(i),
 						 (buf[4 + (i / 8)] >> (i % 8)) & 1);
 			break;
 
 		case 1:
 			/* left wheel */
-			input_report_abs(dev->input_dev, KONTROLS4_ABS(36), buf[9] | ((buf[8] & 0x3) << 8));
+			input_report_abs(cdev->input_dev, KONTROLS4_ABS(36), buf[9] | ((buf[8] & 0x3) << 8));
 			/* right wheel */
-			input_report_abs(dev->input_dev, KONTROLS4_ABS(37), buf[13] | ((buf[12] & 0x3) << 8));
+			input_report_abs(cdev->input_dev, KONTROLS4_ABS(37), buf[13] | ((buf[12] & 0x3) << 8));
 
 			/* rotary encoders */
-			input_report_abs(dev->input_dev, KONTROLS4_ABS(38), buf[3] & 0xf);
-			input_report_abs(dev->input_dev, KONTROLS4_ABS(39), buf[4] >> 4);
-			input_report_abs(dev->input_dev, KONTROLS4_ABS(40), buf[4] & 0xf);
-			input_report_abs(dev->input_dev, KONTROLS4_ABS(41), buf[5] >> 4);
-			input_report_abs(dev->input_dev, KONTROLS4_ABS(42), buf[5] & 0xf);
-			input_report_abs(dev->input_dev, KONTROLS4_ABS(43), buf[6] >> 4);
-			input_report_abs(dev->input_dev, KONTROLS4_ABS(44), buf[6] & 0xf);
-			input_report_abs(dev->input_dev, KONTROLS4_ABS(45), buf[7] >> 4);
-			input_report_abs(dev->input_dev, KONTROLS4_ABS(46), buf[7] & 0xf);
+			input_report_abs(cdev->input_dev, KONTROLS4_ABS(38), buf[3] & 0xf);
+			input_report_abs(cdev->input_dev, KONTROLS4_ABS(39), buf[4] >> 4);
+			input_report_abs(cdev->input_dev, KONTROLS4_ABS(40), buf[4] & 0xf);
+			input_report_abs(cdev->input_dev, KONTROLS4_ABS(41), buf[5] >> 4);
+			input_report_abs(cdev->input_dev, KONTROLS4_ABS(42), buf[5] & 0xf);
+			input_report_abs(cdev->input_dev, KONTROLS4_ABS(43), buf[6] >> 4);
+			input_report_abs(cdev->input_dev, KONTROLS4_ABS(44), buf[6] & 0xf);
+			input_report_abs(cdev->input_dev, KONTROLS4_ABS(45), buf[7] >> 4);
+			input_report_abs(cdev->input_dev, KONTROLS4_ABS(46), buf[7] & 0xf);
 
 			break;
 		case 2:
 			/* Volume Fader Channel D */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(0), buf, 1);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(0), buf, 1);
 			/* Volume Fader Channel B */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(1), buf, 2);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(1), buf, 2);
 			/* Volume Fader Channel A */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(2), buf, 3);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(2), buf, 3);
 			/* Volume Fader Channel C */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(3), buf, 4);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(3), buf, 4);
 			/* Loop Volume */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(4), buf, 6);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(4), buf, 6);
 			/* Crossfader */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(7), buf, 7);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(7), buf, 7);
 
 			break;
 
 		case 3:
 			/* Tempo Fader R */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(6), buf, 3);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(6), buf, 3);
 			/* Tempo Fader L */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(5), buf, 4);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(5), buf, 4);
 			/* Mic Volume */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(8), buf, 6);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(8), buf, 6);
 			/* Cue Mix */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(9), buf, 7);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(9), buf, 7);
 
 			break;
 
 		case 4:
 			/* Wheel distance sensor L */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(10), buf, 1);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(10), buf, 1);
 			/* Wheel distance sensor R */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(11), buf, 2);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(11), buf, 2);
 			/* Channel D EQ - Filter */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(12), buf, 3);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(12), buf, 3);
 			/* Channel D EQ - Low */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(13), buf, 4);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(13), buf, 4);
 			/* Channel D EQ - Mid */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(14), buf, 5);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(14), buf, 5);
 			/* Channel D EQ - Hi */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(15), buf, 6);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(15), buf, 6);
 			/* FX2 - dry/wet */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(16), buf, 7);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(16), buf, 7);
 
 			break;
 
 		case 5:
 			/* FX2 - 1 */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(17), buf, 1);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(17), buf, 1);
 			/* FX2 - 2 */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(18), buf, 2);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(18), buf, 2);
 			/* FX2 - 3 */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(19), buf, 3);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(19), buf, 3);
 			/* Channel B EQ - Filter */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(20), buf, 4);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(20), buf, 4);
 			/* Channel B EQ - Low */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(21), buf, 5);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(21), buf, 5);
 			/* Channel B EQ - Mid */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(22), buf, 6);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(22), buf, 6);
 			/* Channel B EQ - Hi */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(23), buf, 7);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(23), buf, 7);
 
 			break;
 
 		case 6:
 			/* Channel A EQ - Filter */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(24), buf, 1);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(24), buf, 1);
 			/* Channel A EQ - Low */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(25), buf, 2);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(25), buf, 2);
 			/* Channel A EQ - Mid */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(26), buf, 3);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(26), buf, 3);
 			/* Channel A EQ - Hi */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(27), buf, 4);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(27), buf, 4);
 			/* Channel C EQ - Filter */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(28), buf, 5);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(28), buf, 5);
 			/* Channel C EQ - Low */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(29), buf, 6);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(29), buf, 6);
 			/* Channel C EQ - Mid */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(30), buf, 7);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(30), buf, 7);
 
 			break;
 
 		case 7:
 			/* Channel C EQ - Hi */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(31), buf, 1);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(31), buf, 1);
 			/* FX1 - wet/dry */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(32), buf, 2);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(32), buf, 2);
 			/* FX1 - 1 */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(33), buf, 3);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(33), buf, 3);
 			/* FX1 - 2 */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(34), buf, 4);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(34), buf, 4);
 			/* FX1 - 3 */
-			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(35), buf, 5);
+			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(35), buf, 5);
 
 			break;
 
 		default:
-			debug("%s(): bogus block (id %d)\n",
+			dev_dbg(dev, "%s(): bogus block (id %d)\n",
 				__func__, block_id);
 			return;
 		}
@@ -475,81 +478,82 @@ static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *dev,
 		buf += TKS4_MSGBLOCK_SIZE;
 	}
 
-	input_sync(dev->input_dev);
+	input_sync(cdev->input_dev);
 }
 
 #define MASCHINE_MSGBLOCK_SIZE 2
 
-static void snd_usb_caiaq_maschine_dispatch(struct snd_usb_caiaqdev *dev,
+static void snd_usb_caiaq_maschine_dispatch(struct snd_usb_caiaqdev *cdev,
 					const unsigned char *buf,
 					unsigned int len)
 {
 	unsigned int i, pad_id;
-	uint16_t pressure;
+	__le16 *pressure = (__le16 *) buf;
 
 	for (i = 0; i < MASCHINE_PADS; i++) {
-		pressure = be16_to_cpu(buf[i * 2] << 8 | buf[(i * 2) + 1]);
-		pad_id = pressure >> 12;
-
-		input_report_abs(dev->input_dev, MASCHINE_PAD(pad_id), pressure & 0xfff);
+		pad_id = le16_to_cpu(*pressure) >> 12;
+		input_report_abs(cdev->input_dev, MASCHINE_PAD(pad_id),
+				 le16_to_cpu(*pressure) & 0xfff);
+		pressure++;
 	}
 
-	input_sync(dev->input_dev);
+	input_sync(cdev->input_dev);
 }
 
 static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb)
 {
-	struct snd_usb_caiaqdev *dev = urb->context;
+	struct snd_usb_caiaqdev *cdev = urb->context;
 	unsigned char *buf = urb->transfer_buffer;
+	struct device *dev = &urb->dev->dev;
 	int ret;
 
-	if (urb->status || !dev || urb != dev->ep4_in_urb)
+	if (urb->status || !cdev || urb != cdev->ep4_in_urb)
 		return;
 
-	switch (dev->chip.usb_id) {
+	switch (cdev->chip.usb_id) {
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
 		if (urb->actual_length < 24)
 			goto requeue;
 
 		if (buf[0] & 0x3)
-			snd_caiaq_input_read_io(dev, buf + 1, 7);
+			snd_caiaq_input_read_io(cdev, buf + 1, 7);
 
 		if (buf[0] & 0x4)
-			snd_caiaq_input_read_analog(dev, buf + 8, 16);
+			snd_caiaq_input_read_analog(cdev, buf + 8, 16);
 
 		break;
 
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
-		snd_usb_caiaq_tks4_dispatch(dev, buf, urb->actual_length);
+		snd_usb_caiaq_tks4_dispatch(cdev, buf, urb->actual_length);
 		break;
 
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER):
 		if (urb->actual_length < (MASCHINE_PADS * MASCHINE_MSGBLOCK_SIZE))
 			goto requeue;
 
-		snd_usb_caiaq_maschine_dispatch(dev, buf, urb->actual_length);
+		snd_usb_caiaq_maschine_dispatch(cdev, buf, urb->actual_length);
 		break;
 	}
 
 requeue:
-	dev->ep4_in_urb->actual_length = 0;
-	ret = usb_submit_urb(dev->ep4_in_urb, GFP_ATOMIC);
+	cdev->ep4_in_urb->actual_length = 0;
+	ret = usb_submit_urb(cdev->ep4_in_urb, GFP_ATOMIC);
 	if (ret < 0)
-		log("unable to submit urb. OOM!?\n");
+		dev_err(dev, "unable to submit urb. OOM!?\n");
 }
 
 static int snd_usb_caiaq_input_open(struct input_dev *idev)
 {
-	struct snd_usb_caiaqdev *dev = input_get_drvdata(idev);
+	struct snd_usb_caiaqdev *cdev = input_get_drvdata(idev);
 
-	if (!dev)
+	if (!cdev)
 		return -EINVAL;
 
-	switch (dev->chip.usb_id) {
+	switch (cdev->chip.usb_id) {
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER):
-		if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0)
+		if (usb_submit_urb(cdev->ep4_in_urb, GFP_KERNEL) != 0)
 			return -EIO;
 		break;
 	}
@@ -559,43 +563,43 @@ static int snd_usb_caiaq_input_open(struct input_dev *idev)
 
 static void snd_usb_caiaq_input_close(struct input_dev *idev)
 {
-	struct snd_usb_caiaqdev *dev = input_get_drvdata(idev);
+	struct snd_usb_caiaqdev *cdev = input_get_drvdata(idev);
 
-	if (!dev)
+	if (!cdev)
 		return;
 
-	switch (dev->chip.usb_id) {
+	switch (cdev->chip.usb_id) {
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER):
-		usb_kill_urb(dev->ep4_in_urb);
+		usb_kill_urb(cdev->ep4_in_urb);
 		break;
 	}
 }
 
-void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev,
+void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *cdev,
 				  char *buf,
 				  unsigned int len)
 {
-	if (!dev->input_dev || len < 1)
+	if (!cdev->input_dev || len < 1)
 		return;
 
 	switch (buf[0]) {
 	case EP1_CMD_READ_ANALOG:
-		snd_caiaq_input_read_analog(dev, buf + 1, len - 1);
+		snd_caiaq_input_read_analog(cdev, buf + 1, len - 1);
 		break;
 	case EP1_CMD_READ_ERP:
-		snd_caiaq_input_read_erp(dev, buf + 1, len - 1);
+		snd_caiaq_input_read_erp(cdev, buf + 1, len - 1);
 		break;
 	case EP1_CMD_READ_IO:
-		snd_caiaq_input_read_io(dev, buf + 1, len - 1);
+		snd_caiaq_input_read_io(cdev, buf + 1, len - 1);
 		break;
 	}
 }
 
-int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
+int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev)
 {
-	struct usb_device *usb_dev = dev->chip.dev;
+	struct usb_device *usb_dev = cdev->chip.dev;
 	struct input_dev *input;
 	int i, ret = 0;
 
@@ -603,49 +607,49 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
 	if (!input)
 		return -ENOMEM;
 
-	usb_make_path(usb_dev, dev->phys, sizeof(dev->phys));
-	strlcat(dev->phys, "/input0", sizeof(dev->phys));
+	usb_make_path(usb_dev, cdev->phys, sizeof(cdev->phys));
+	strlcat(cdev->phys, "/input0", sizeof(cdev->phys));
 
-	input->name = dev->product_name;
-	input->phys = dev->phys;
+	input->name = cdev->product_name;
+	input->phys = cdev->phys;
 	usb_to_input_id(usb_dev, &input->id);
 	input->dev.parent = &usb_dev->dev;
 
-	input_set_drvdata(input, dev);
+	input_set_drvdata(input, cdev);
 
-	switch (dev->chip.usb_id) {
+	switch (cdev->chip.usb_id) {
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
 		input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 		input->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
 			BIT_MASK(ABS_Z);
-		BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_rk2));
-		memcpy(dev->keycode, keycode_rk2, sizeof(keycode_rk2));
+		BUILD_BUG_ON(sizeof(cdev->keycode) < sizeof(keycode_rk2));
+		memcpy(cdev->keycode, keycode_rk2, sizeof(keycode_rk2));
 		input->keycodemax = ARRAY_SIZE(keycode_rk2);
 		input_set_abs_params(input, ABS_X, 0, 4096, 0, 10);
 		input_set_abs_params(input, ABS_Y, 0, 4096, 0, 10);
 		input_set_abs_params(input, ABS_Z, 0, 4096, 0, 10);
-		snd_usb_caiaq_set_auto_msg(dev, 1, 10, 0);
+		snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 0);
 		break;
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
 		input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 		input->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
 			BIT_MASK(ABS_Z);
-		BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_rk3));
-		memcpy(dev->keycode, keycode_rk3, sizeof(keycode_rk3));
+		BUILD_BUG_ON(sizeof(cdev->keycode) < sizeof(keycode_rk3));
+		memcpy(cdev->keycode, keycode_rk3, sizeof(keycode_rk3));
 		input->keycodemax = ARRAY_SIZE(keycode_rk3);
 		input_set_abs_params(input, ABS_X, 0, 1024, 0, 10);
 		input_set_abs_params(input, ABS_Y, 0, 1024, 0, 10);
 		input_set_abs_params(input, ABS_Z, 0, 1024, 0, 10);
-		snd_usb_caiaq_set_auto_msg(dev, 1, 10, 0);
+		snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 0);
 		break;
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
 		input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 		input->absbit[0] = BIT_MASK(ABS_X);
-		BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_ak1));
-		memcpy(dev->keycode, keycode_ak1, sizeof(keycode_ak1));
+		BUILD_BUG_ON(sizeof(cdev->keycode) < sizeof(keycode_ak1));
+		memcpy(cdev->keycode, keycode_ak1, sizeof(keycode_ak1));
 		input->keycodemax = ARRAY_SIZE(keycode_ak1);
 		input_set_abs_params(input, ABS_X, 0, 999, 0, 10);
-		snd_usb_caiaq_set_auto_msg(dev, 1, 0, 5);
+		snd_usb_caiaq_set_auto_msg(cdev, 1, 0, 5);
 		break;
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
@@ -657,8 +661,8 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
 				   BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
 				   BIT_MASK(ABS_Z);
 		input->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC);
-		BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_kore));
-		memcpy(dev->keycode, keycode_kore, sizeof(keycode_kore));
+		BUILD_BUG_ON(sizeof(cdev->keycode) < sizeof(keycode_kore));
+		memcpy(cdev->keycode, keycode_kore, sizeof(keycode_kore));
 		input->keycodemax = ARRAY_SIZE(keycode_kore);
 		input_set_abs_params(input, ABS_HAT0X, 0, 999, 0, 10);
 		input_set_abs_params(input, ABS_HAT0Y, 0, 999, 0, 10);
@@ -672,7 +676,7 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
 		input_set_abs_params(input, ABS_Y, 0, 4096, 0, 10);
 		input_set_abs_params(input, ABS_Z, 0, 4096, 0, 10);
 		input_set_abs_params(input, ABS_MISC, 0, 255, 0, 1);
-		snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
+		snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 5);
 		break;
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
 		input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
@@ -683,9 +687,9 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
 				   BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
 				   BIT_MASK(ABS_Z);
 		input->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC);
-		BUILD_BUG_ON(sizeof(dev->keycode) < KONTROLX1_INPUTS);
+		BUILD_BUG_ON(sizeof(cdev->keycode) < KONTROLX1_INPUTS);
 		for (i = 0; i < KONTROLX1_INPUTS; i++)
-			dev->keycode[i] = BTN_MISC + i;
+			cdev->keycode[i] = BTN_MISC + i;
 		input->keycodemax = KONTROLX1_INPUTS;
 
 		/* analog potentiometers */
@@ -704,26 +708,26 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
 		input_set_abs_params(input, ABS_Z, 0, 0xf, 0, 1);
 		input_set_abs_params(input, ABS_MISC, 0, 0xf, 0, 1);
 
-		dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL);
-		if (!dev->ep4_in_urb) {
+		cdev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!cdev->ep4_in_urb) {
 			ret = -ENOMEM;
 			goto exit_free_idev;
 		}
 
-		usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev,
+		usb_fill_bulk_urb(cdev->ep4_in_urb, usb_dev,
 				  usb_rcvbulkpipe(usb_dev, 0x4),
-				  dev->ep4_in_buf, EP4_BUFSIZE,
-				  snd_usb_caiaq_ep4_reply_dispatch, dev);
+				  cdev->ep4_in_buf, EP4_BUFSIZE,
+				  snd_usb_caiaq_ep4_reply_dispatch, cdev);
 
-		snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
+		snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 5);
 
 		break;
 
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
 		input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
-		BUILD_BUG_ON(sizeof(dev->keycode) < KONTROLS4_BUTTONS);
+		BUILD_BUG_ON(sizeof(cdev->keycode) < KONTROLS4_BUTTONS);
 		for (i = 0; i < KONTROLS4_BUTTONS; i++)
-			dev->keycode[i] = KONTROLS4_BUTTON(i);
+			cdev->keycode[i] = KONTROLS4_BUTTON(i);
 		input->keycodemax = KONTROLS4_BUTTONS;
 
 		for (i = 0; i < KONTROLS4_AXIS; i++) {
@@ -743,18 +747,18 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
 		for (i = 0; i < 9; i++)
 			input_set_abs_params(input, KONTROLS4_ABS(38+i), 0, 0xf, 0, 1);
 
-		dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL);
-		if (!dev->ep4_in_urb) {
+		cdev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!cdev->ep4_in_urb) {
 			ret = -ENOMEM;
 			goto exit_free_idev;
 		}
 
-		usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev,
+		usb_fill_bulk_urb(cdev->ep4_in_urb, usb_dev,
 				  usb_rcvbulkpipe(usb_dev, 0x4),
-				  dev->ep4_in_buf, EP4_BUFSIZE,
-				  snd_usb_caiaq_ep4_reply_dispatch, dev);
+				  cdev->ep4_in_buf, EP4_BUFSIZE,
+				  snd_usb_caiaq_ep4_reply_dispatch, cdev);
 
-		snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
+		snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 5);
 
 		break;
 
@@ -767,8 +771,8 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
 			BIT_MASK(ABS_RX) | BIT_MASK(ABS_RY) |
 			BIT_MASK(ABS_RZ);
 
-		BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_maschine));
-		memcpy(dev->keycode, keycode_maschine, sizeof(keycode_maschine));
+		BUILD_BUG_ON(sizeof(cdev->keycode) < sizeof(keycode_maschine));
+		memcpy(cdev->keycode, keycode_maschine, sizeof(keycode_maschine));
 		input->keycodemax = ARRAY_SIZE(keycode_maschine);
 
 		for (i = 0; i < MASCHINE_PADS; i++) {
@@ -788,18 +792,18 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
 		input_set_abs_params(input, ABS_RY, 0, 999, 0, 10);
 		input_set_abs_params(input, ABS_RZ, 0, 999, 0, 10);
 
-		dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL);
-		if (!dev->ep4_in_urb) {
+		cdev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!cdev->ep4_in_urb) {
 			ret = -ENOMEM;
 			goto exit_free_idev;
 		}
 
-		usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev,
+		usb_fill_bulk_urb(cdev->ep4_in_urb, usb_dev,
 				  usb_rcvbulkpipe(usb_dev, 0x4),
-				  dev->ep4_in_buf, EP4_BUFSIZE,
-				  snd_usb_caiaq_ep4_reply_dispatch, dev);
+				  cdev->ep4_in_buf, EP4_BUFSIZE,
+				  snd_usb_caiaq_ep4_reply_dispatch, cdev);
 
-		snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
+		snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 5);
 		break;
 
 	default:
@@ -809,12 +813,12 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
 
 	input->open = snd_usb_caiaq_input_open;
 	input->close = snd_usb_caiaq_input_close;
-	input->keycode = dev->keycode;
+	input->keycode = cdev->keycode;
 	input->keycodesize = sizeof(unsigned short);
 	for (i = 0; i < input->keycodemax; i++)
-		__set_bit(dev->keycode[i], input->keybit);
+		__set_bit(cdev->keycode[i], input->keybit);
 
-	dev->input_dev = input;
+	cdev->input_dev = input;
 
 	ret = input_register_device(input);
 	if (ret < 0)
@@ -824,19 +828,19 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
 
 exit_free_idev:
 	input_free_device(input);
-	dev->input_dev = NULL;
+	cdev->input_dev = NULL;
 	return ret;
 }
 
-void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev)
+void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *cdev)
 {
-	if (!dev || !dev->input_dev)
+	if (!cdev || !cdev->input_dev)
 		return;
 
-	usb_kill_urb(dev->ep4_in_urb);
-	usb_free_urb(dev->ep4_in_urb);
-	dev->ep4_in_urb = NULL;
+	usb_kill_urb(cdev->ep4_in_urb);
+	usb_free_urb(cdev->ep4_in_urb);
+	cdev->ep4_in_urb = NULL;
 
-	input_unregister_device(dev->input_dev);
-	dev->input_dev = NULL;
+	input_unregister_device(cdev->input_dev);
+	cdev->input_dev = NULL;
 }
diff --git a/sound/usb/caiaq/input.h b/sound/usb/caiaq/input.h
index ced535577864..6014e2713a60 100644
--- a/sound/usb/caiaq/input.h
+++ b/sound/usb/caiaq/input.h
@@ -1,8 +1,8 @@
 #ifndef CAIAQ_INPUT_H
 #define CAIAQ_INPUT_H
 
-void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev, char *buf, unsigned int len);
-int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev);
-void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev);
+void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *cdev, char *buf, unsigned int len);
+int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev);
+void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *cdev);
 
 #endif
diff --git a/sound/usb/caiaq/midi.c b/sound/usb/caiaq/midi.c
index a1a47088fd0c..2d7588461b33 100644
--- a/sound/usb/caiaq/midi.c
+++ b/sound/usb/caiaq/midi.c
@@ -16,6 +16,7 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */
 
+#include <linux/device.h>
 #include <linux/usb.h>
 #include <linux/gfp.h>
 #include <sound/rawmidi.h>
@@ -37,12 +38,12 @@ static int snd_usb_caiaq_midi_input_close(struct snd_rawmidi_substream *substrea
 
 static void snd_usb_caiaq_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
 {
-	struct snd_usb_caiaqdev *dev = substream->rmidi->private_data;
+	struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data;
 
-	if (!dev)
+	if (!cdev)
 		return;
 
-	dev->midi_receive_substream = up ? substream : NULL;
+	cdev->midi_receive_substream = up ? substream : NULL;
 }
 
 
@@ -53,49 +54,50 @@ static int snd_usb_caiaq_midi_output_open(struct snd_rawmidi_substream *substrea
 
 static int snd_usb_caiaq_midi_output_close(struct snd_rawmidi_substream *substream)
 {
-	struct snd_usb_caiaqdev *dev = substream->rmidi->private_data;
-	if (dev->midi_out_active) {
-		usb_kill_urb(&dev->midi_out_urb);
-		dev->midi_out_active = 0;
+	struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data;
+	if (cdev->midi_out_active) {
+		usb_kill_urb(&cdev->midi_out_urb);
+		cdev->midi_out_active = 0;
 	}
 	return 0;
 }
 
-static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *dev,
+static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *cdev,
 				    struct snd_rawmidi_substream *substream)
 {
 	int len, ret;
+	struct device *dev = caiaqdev_to_dev(cdev);
 
-	dev->midi_out_buf[0] = EP1_CMD_MIDI_WRITE;
-	dev->midi_out_buf[1] = 0; /* port */
-	len = snd_rawmidi_transmit(substream, dev->midi_out_buf + 3,
+	cdev->midi_out_buf[0] = EP1_CMD_MIDI_WRITE;
+	cdev->midi_out_buf[1] = 0; /* port */
+	len = snd_rawmidi_transmit(substream, cdev->midi_out_buf + 3,
 				   EP1_BUFSIZE - 3);
 
 	if (len <= 0)
 		return;
 
-	dev->midi_out_buf[2] = len;
-	dev->midi_out_urb.transfer_buffer_length = len+3;
+	cdev->midi_out_buf[2] = len;
+	cdev->midi_out_urb.transfer_buffer_length = len+3;
 
-	ret = usb_submit_urb(&dev->midi_out_urb, GFP_ATOMIC);
+	ret = usb_submit_urb(&cdev->midi_out_urb, GFP_ATOMIC);
 	if (ret < 0)
-		log("snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed,"
-		    "ret=%d, len=%d\n",
-		    substream, ret, len);
+		dev_err(dev,
+			"snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed,"
+			"ret=%d, len=%d\n", substream, ret, len);
 	else
-		dev->midi_out_active = 1;
+		cdev->midi_out_active = 1;
 }
 
 static void snd_usb_caiaq_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
 {
-	struct snd_usb_caiaqdev *dev = substream->rmidi->private_data;
+	struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data;
 
 	if (up) {
-		dev->midi_out_substream = substream;
-		if (!dev->midi_out_active)
-			snd_usb_caiaq_midi_send(dev, substream);
+		cdev->midi_out_substream = substream;
+		if (!cdev->midi_out_active)
+			snd_usb_caiaq_midi_send(cdev, substream);
 	} else {
-		dev->midi_out_substream = NULL;
+		cdev->midi_out_substream = NULL;
 	}
 }
 
@@ -114,13 +116,13 @@ static struct snd_rawmidi_ops snd_usb_caiaq_midi_input =
 	.trigger =      snd_usb_caiaq_midi_input_trigger,
 };
 
-void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev,
+void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *cdev,
 				     int port, const char *buf, int len)
 {
-	if (!dev->midi_receive_substream)
+	if (!cdev->midi_receive_substream)
 		return;
 
-	snd_rawmidi_receive(dev->midi_receive_substream, buf, len);
+	snd_rawmidi_receive(cdev->midi_receive_substream, buf, len);
 }
 
 int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device)
@@ -160,15 +162,14 @@ int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device)
 
 void snd_usb_caiaq_midi_output_done(struct urb* urb)
 {
-	struct snd_usb_caiaqdev *dev = urb->context;
+	struct snd_usb_caiaqdev *cdev = urb->context;
 
-	dev->midi_out_active = 0;
+	cdev->midi_out_active = 0;
 	if (urb->status != 0)
 		return;
 
-	if (!dev->midi_out_substream)
+	if (!cdev->midi_out_substream)
 		return;
 
-	snd_usb_caiaq_midi_send(dev, dev->midi_out_substream);
+	snd_usb_caiaq_midi_send(cdev, cdev->midi_out_substream);
 }
-
diff --git a/sound/usb/caiaq/midi.h b/sound/usb/caiaq/midi.h
index 380f984babc9..60bf3442b283 100644
--- a/sound/usb/caiaq/midi.h
+++ b/sound/usb/caiaq/midi.h
@@ -1,8 +1,9 @@
 #ifndef CAIAQ_MIDI_H
 #define CAIAQ_MIDI_H
 
-int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *dev);
-void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev, int port, const char *buf, int len);
+int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *cdev);
+void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *cdev,
+				     int port, const char *buf, int len);
 void snd_usb_caiaq_midi_output_done(struct urb *urb);
 
 #endif /* CAIAQ_MIDI_H */
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 2da8ad75fd96..1a033177b83f 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -82,6 +82,7 @@ static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 };
 static int nrpacks = 8;		/* max. number of packets per urb */
 static int device_setup[SNDRV_CARDS]; /* device parameter for this card */
 static bool ignore_ctl_error;
+static bool autoclock = true;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the USB audio adapter.");
@@ -100,6 +101,8 @@ MODULE_PARM_DESC(device_setup, "Specific device setup (if needed).");
 module_param(ignore_ctl_error, bool, 0444);
 MODULE_PARM_DESC(ignore_ctl_error,
 		 "Ignore errors from USB controller for mixer interfaces.");
+module_param(autoclock, bool, 0444);
+MODULE_PARM_DESC(autoclock, "Enable auto-clock selection for UAC2 devices (default: yes).");
 
 /*
  * we keep the snd_usb_audio_t instances by ourselves for merging
@@ -354,6 +357,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
 	chip->card = card;
 	chip->setup = device_setup[idx];
 	chip->nrpacks = nrpacks;
+	chip->autoclock = autoclock;
 	chip->probing = 1;
 
 	chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
@@ -627,7 +631,9 @@ int snd_usb_autoresume(struct snd_usb_audio *chip)
 	int err = -ENODEV;
 
 	down_read(&chip->shutdown_rwsem);
-	if (!chip->shutdown && !chip->probing)
+	if (chip->probing)
+		err = 0;
+	else if (!chip->shutdown)
 		err = usb_autopm_get_interface(chip->pm_intf);
 	up_read(&chip->shutdown_rwsem);
 
@@ -645,7 +651,6 @@ void snd_usb_autosuspend(struct snd_usb_audio *chip)
 static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
 {
 	struct snd_usb_audio *chip = usb_get_intfdata(intf);
-	struct list_head *p;
 	struct snd_usb_stream *as;
 	struct usb_mixer_interface *mixer;
 
@@ -655,8 +660,7 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
 	if (!PMSG_IS_AUTO(message)) {
 		snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
 		if (!chip->num_suspended_intf++) {
-			list_for_each(p, &chip->pcm_list) {
-				as = list_entry(p, struct snd_usb_stream, list);
+			list_for_each_entry(as, &chip->pcm_list, list) {
 				snd_pcm_suspend_all(as->pcm);
 				as->substream[0].need_setup_ep =
 					as->substream[1].need_setup_ep = true;
@@ -716,8 +720,7 @@ static struct usb_device_id usb_audio_ids [] = {
       .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL },
     { }						/* Terminating entry */
 };
-
-MODULE_DEVICE_TABLE (usb, usb_audio_ids);
+MODULE_DEVICE_TABLE(usb, usb_audio_ids);
 
 /*
  * entry point for linux usb interface
diff --git a/sound/usb/card.h b/sound/usb/card.h
index 8a751b4887ea..bf2889a2cae5 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -28,6 +28,8 @@ struct audioformat {
 	unsigned int *rate_table;	/* rate table */
 	unsigned char clock;		/* associated clock */
 	struct snd_pcm_chmap_elem *chmap; /* (optional) channel map */
+	bool dsd_dop;			/* add DOP headers in case of DSD samples */
+	bool dsd_bitrev;		/* reverse the bits of each DSD sample */
 };
 
 struct snd_usb_substream;
@@ -116,6 +118,7 @@ struct snd_usb_substream {
 	unsigned int altset_idx;     /* USB data format: index of alternate setting */
 	unsigned int txfr_quirk:1;	/* allow sub-frame alignment */
 	unsigned int fmt_type;		/* USB audio format type (1-3) */
+	unsigned int pkt_offset_adj;	/* Bytes to drop from beginning of packets (for non-compliant devices) */
 
 	unsigned int running: 1;	/* running status */
 
@@ -138,6 +141,12 @@ struct snd_usb_substream {
 
 	int last_frame_number;          /* stored frame number */
 	int last_delay;                 /* stored delay */
+
+	struct {
+		int marker;
+		int channel;
+		int byte_idx;
+	} dsd_dop;
 };
 
 struct snd_usb_stream {
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index 9e2703a25156..3a2ce390e278 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -32,6 +32,7 @@
 #include "card.h"
 #include "helper.h"
 #include "clock.h"
+#include "quirks.h"
 
 static struct uac_clock_source_descriptor *
 	snd_usb_find_clock_source(struct usb_host_interface *ctrl_iface,
@@ -99,6 +100,41 @@ static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_i
 	return buf;
 }
 
+static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_id,
+					unsigned char pin)
+{
+	int ret;
+
+	ret = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0),
+			      UAC2_CS_CUR,
+			      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+			      UAC2_CX_CLOCK_SELECTOR << 8,
+			      snd_usb_ctrl_intf(chip) | (selector_id << 8),
+			      &pin, sizeof(pin));
+	if (ret < 0)
+		return ret;
+
+	if (ret != sizeof(pin)) {
+		snd_printk(KERN_ERR
+			"usb-audio:%d: setting selector (id %d) unexpected length %d\n",
+			chip->dev->devnum, selector_id, ret);
+		return -EINVAL;
+	}
+
+	ret = uac_clock_selector_get_val(chip, selector_id);
+	if (ret < 0)
+		return ret;
+
+	if (ret != pin) {
+		snd_printk(KERN_ERR
+			"usb-audio:%d: setting selector (id %d) to %x failed (current: %d)\n",
+			chip->dev->devnum, selector_id, pin, ret);
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
 static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id)
 {
 	int err;
@@ -131,7 +167,8 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id)
 }
 
 static int __uac_clock_find_source(struct snd_usb_audio *chip,
-				   int entity_id, unsigned long *visited)
+				   int entity_id, unsigned long *visited,
+				   bool validate)
 {
 	struct uac_clock_source_descriptor *source;
 	struct uac_clock_selector_descriptor *selector;
@@ -148,12 +185,19 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
 
 	/* first, see if the ID we're looking for is a clock source already */
 	source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id);
-	if (source)
-		return source->bClockID;
+	if (source) {
+		entity_id = source->bClockID;
+		if (validate && !uac_clock_source_is_valid(chip, entity_id)) {
+			snd_printk(KERN_ERR "usb-audio:%d: clock source %d is not valid, cannot use\n",
+				   chip->dev->devnum, entity_id);
+			return -ENXIO;
+		}
+		return entity_id;
+	}
 
 	selector = snd_usb_find_clock_selector(chip->ctrl_intf, entity_id);
 	if (selector) {
-		int ret;
+		int ret, i, cur;
 
 		/* the entity ID we are looking for is a selector.
 		 * find out what it currently selects */
@@ -164,22 +208,49 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
 		/* Selector values are one-based */
 
 		if (ret > selector->bNrInPins || ret < 1) {
-			printk(KERN_ERR
+			snd_printk(KERN_ERR
 				"%s(): selector reported illegal value, id %d, ret %d\n",
 				__func__, selector->bClockID, ret);
 
 			return -EINVAL;
 		}
 
-		return __uac_clock_find_source(chip, selector->baCSourceID[ret-1],
-					       visited);
+		cur = ret;
+		ret = __uac_clock_find_source(chip, selector->baCSourceID[ret - 1],
+					       visited, validate);
+		if (!validate || ret > 0 || !chip->autoclock)
+			return ret;
+
+		/* The current clock source is invalid, try others. */
+		for (i = 1; i <= selector->bNrInPins; i++) {
+			int err;
+
+			if (i == cur)
+				continue;
+
+			ret = __uac_clock_find_source(chip, selector->baCSourceID[i - 1],
+				visited, true);
+			if (ret < 0)
+				continue;
+
+			err = uac_clock_selector_set_val(chip, entity_id, i);
+			if (err < 0)
+				continue;
+
+			snd_printk(KERN_INFO
+				"usb-audio:%d: found and selected valid clock source %d\n",
+				chip->dev->devnum, ret);
+			return ret;
+		}
+
+		return -ENXIO;
 	}
 
 	/* FIXME: multipliers only act as pass-thru element for now */
 	multiplier = snd_usb_find_clock_multiplier(chip->ctrl_intf, entity_id);
 	if (multiplier)
 		return __uac_clock_find_source(chip, multiplier->bCSourceID,
-						visited);
+						visited, validate);
 
 	return -EINVAL;
 }
@@ -195,11 +266,12 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
  *
  * Returns the clock source UnitID (>=0) on success, or an error.
  */
-int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id)
+int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id,
+			      bool validate)
 {
 	DECLARE_BITMAP(visited, 256);
 	memset(visited, 0, sizeof(visited));
-	return __uac_clock_find_source(chip, entity_id, visited);
+	return __uac_clock_find_source(chip, entity_id, visited, validate);
 }
 
 static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
@@ -247,66 +319,73 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
 	return 0;
 }
 
+static int get_sample_rate_v2(struct snd_usb_audio *chip, int iface,
+			      int altsetting, int clock)
+{
+	struct usb_device *dev = chip->dev;
+	__le32 data;
+	int err;
+
+	err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
+			      USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+			      UAC2_CS_CONTROL_SAM_FREQ << 8,
+			      snd_usb_ctrl_intf(chip) | (clock << 8),
+			      &data, sizeof(data));
+	if (err < 0) {
+		snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2): err %d\n",
+			   dev->devnum, iface, altsetting, err);
+		return 0;
+	}
+
+	return le32_to_cpu(data);
+}
+
 static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
 			      struct usb_host_interface *alts,
 			      struct audioformat *fmt, int rate)
 {
 	struct usb_device *dev = chip->dev;
-	unsigned char data[4];
+	__le32 data;
 	int err, cur_rate, prev_rate;
-	int clock = snd_usb_clock_find_source(chip, fmt->clock);
+	int clock;
+	bool writeable;
+	struct uac_clock_source_descriptor *cs_desc;
 
+	clock = snd_usb_clock_find_source(chip, fmt->clock, true);
 	if (clock < 0)
 		return clock;
 
-	if (!uac_clock_source_is_valid(chip, clock)) {
-		/* TODO: should we try to find valid clock setups by ourself? */
-		snd_printk(KERN_ERR "%d:%d:%d: clock source %d is not valid, cannot use\n",
-			   dev->devnum, iface, fmt->altsetting, clock);
-		return -ENXIO;
-	}
-
-	err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
-			      USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
-			      UAC2_CS_CONTROL_SAM_FREQ << 8,
-			      snd_usb_ctrl_intf(chip) | (clock << 8),
-			      data, sizeof(data));
-	if (err < 0) {
-		snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n",
-			   dev->devnum, iface, fmt->altsetting);
-		prev_rate = 0;
-	} else {
-		prev_rate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
-	}
+	prev_rate = get_sample_rate_v2(chip, iface, fmt->altsetting, clock);
+	if (prev_rate == rate)
+		return 0;
 
-	data[0] = rate;
-	data[1] = rate >> 8;
-	data[2] = rate >> 16;
-	data[3] = rate >> 24;
-	if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
-				   USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
-				   UAC2_CS_CONTROL_SAM_FREQ << 8,
-				   snd_usb_ctrl_intf(chip) | (clock << 8),
-				   data, sizeof(data))) < 0) {
-		snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n",
-			   dev->devnum, iface, fmt->altsetting, rate);
-		return err;
-	}
+	cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, clock);
+	writeable = uac2_control_is_writeable(cs_desc->bmControls, UAC2_CS_CONTROL_SAM_FREQ - 1);
+	if (writeable) {
+		data = cpu_to_le32(rate);
+		err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
+				      USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+				      UAC2_CS_CONTROL_SAM_FREQ << 8,
+				      snd_usb_ctrl_intf(chip) | (clock << 8),
+				      &data, sizeof(data));
+		if (err < 0) {
+			snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2): err %d\n",
+				   dev->devnum, iface, fmt->altsetting, rate, err);
+			return err;
+		}
 
-	err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
-			      USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
-			      UAC2_CS_CONTROL_SAM_FREQ << 8,
-			      snd_usb_ctrl_intf(chip) | (clock << 8),
-			      data, sizeof(data));
-	if (err < 0) {
-		snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n",
-			   dev->devnum, iface, fmt->altsetting);
-		cur_rate = 0;
+		cur_rate = get_sample_rate_v2(chip, iface, fmt->altsetting, clock);
 	} else {
-		cur_rate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+		cur_rate = prev_rate;
 	}
 
 	if (cur_rate != rate) {
+		if (!writeable) {
+			snd_printk(KERN_WARNING
+				   "%d:%d:%d: freq mismatch (RO clock): req %d, clock runs @%d\n",
+				   dev->devnum, iface, fmt->altsetting, rate, cur_rate);
+			return -ENXIO;
+		}
 		snd_printd(KERN_WARNING
 			   "current rate %d is different from the runtime rate %d\n",
 			   cur_rate, rate);
@@ -316,7 +395,9 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
 	 * interface is active. */
 	if (rate != prev_rate) {
 		usb_set_interface(dev, iface, 0);
+		snd_usb_set_interface_quirk(dev);
 		usb_set_interface(dev, iface, fmt->altsetting);
+		snd_usb_set_interface_quirk(dev);
 	}
 
 	return 0;
diff --git a/sound/usb/clock.h b/sound/usb/clock.h
index 46630936d31f..d592e4a29856 100644
--- a/sound/usb/clock.h
+++ b/sound/usb/clock.h
@@ -5,6 +5,7 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
 			     struct usb_host_interface *alts,
 			     struct audioformat *fmt, int rate);
 
-int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id);
+int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id,
+			     bool validate);
 
 #endif /* __USBAUDIO_CLOCK_H */
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 21049b882ee6..7a444b5501d9 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -128,7 +128,7 @@ static const char *usb_error_string(int err)
  * Determine whether an endpoint is driven by an implicit feedback
  * data endpoint source.
  */
-int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep)
+int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep)
 {
 	return  ep->sync_master &&
 		ep->sync_master->type == SND_USB_ENDPOINT_TYPE_DATA &&
@@ -363,7 +363,7 @@ static void snd_complete_urb(struct urb *urb)
 		if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags)))
 			goto exit_clear;
 
-		if (snd_usb_endpoint_implict_feedback_sink(ep)) {
+		if (snd_usb_endpoint_implicit_feedback_sink(ep)) {
 			unsigned long flags;
 
 			spin_lock_irqsave(&ep->lock, flags);
@@ -415,14 +415,12 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
 					      struct usb_host_interface *alts,
 					      int ep_num, int direction, int type)
 {
-	struct list_head *p;
 	struct snd_usb_endpoint *ep;
 	int is_playback = direction == SNDRV_PCM_STREAM_PLAYBACK;
 
 	mutex_lock(&chip->mutex);
 
-	list_for_each(p, &chip->ep_list) {
-		ep = list_entry(p, struct snd_usb_endpoint, list);
+	list_for_each_entry(ep, &chip->ep_list, list) {
 		if (ep->ep_num == ep_num &&
 		    ep->iface == alts->desc.bInterfaceNumber &&
 		    ep->alt_idx == alts->desc.bAlternateSetting) {
@@ -580,6 +578,15 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep,
 	int is_playback = usb_pipeout(ep->pipe);
 	int frame_bits = snd_pcm_format_physical_width(pcm_format) * channels;
 
+	if (pcm_format == SNDRV_PCM_FORMAT_DSD_U16_LE && fmt->dsd_dop) {
+		/*
+		 * When operating in DSD DOP mode, the size of a sample frame
+		 * in hardware differs from the actual physical format width
+		 * because we need to make room for the DOP markers.
+		 */
+		frame_bits += channels << 3;
+	}
+
 	ep->datainterval = fmt->datainterval;
 	ep->stride = frame_bits >> 3;
 	ep->silence_value = pcm_format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0;
@@ -607,7 +614,7 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep,
 	else
 		packs_per_ms = 1;
 
-	if (is_playback && !snd_usb_endpoint_implict_feedback_sink(ep)) {
+	if (is_playback && !snd_usb_endpoint_implicit_feedback_sink(ep)) {
 		urb_packs = max(ep->chip->nrpacks, 1);
 		urb_packs = min(urb_packs, (unsigned int) MAX_PACKS);
 	} else {
@@ -616,11 +623,11 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep,
 
 	urb_packs *= packs_per_ms;
 
-	if (sync_ep && !snd_usb_endpoint_implict_feedback_sink(ep))
+	if (sync_ep && !snd_usb_endpoint_implicit_feedback_sink(ep))
 		urb_packs = min(urb_packs, 1U << sync_ep->syncinterval);
 
 	/* decide how many packets to be used */
-	if (is_playback && !snd_usb_endpoint_implict_feedback_sink(ep)) {
+	if (is_playback && !snd_usb_endpoint_implicit_feedback_sink(ep)) {
 		unsigned int minsize, maxpacks;
 		/* determine how small a packet can be */
 		minsize = (ep->freqn >> (16 - ep->datainterval))
@@ -677,7 +684,7 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep,
 		if (!u->urb->transfer_buffer)
 			goto out_of_memory;
 		u->urb->pipe = ep->pipe;
-		u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+		u->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
 		u->urb->interval = 1 << ep->datainterval;
 		u->urb->context = u;
 		u->urb->complete = snd_complete_urb;
@@ -716,8 +723,7 @@ static int sync_ep_set_params(struct snd_usb_endpoint *ep,
 		u->urb->transfer_dma = ep->sync_dma + i * 4;
 		u->urb->transfer_buffer_length = 4;
 		u->urb->pipe = ep->pipe;
-		u->urb->transfer_flags = URB_ISO_ASAP |
-					 URB_NO_TRANSFER_DMA_MAP;
+		u->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
 		u->urb->number_of_packets = 1;
 		u->urb->interval = 1 << ep->syncinterval;
 		u->urb->context = u;
@@ -847,7 +853,7 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, bool can_sleep)
 
 	set_bit(EP_FLAG_RUNNING, &ep->flags);
 
-	if (snd_usb_endpoint_implict_feedback_sink(ep)) {
+	if (snd_usb_endpoint_implicit_feedback_sink(ep)) {
 		for (i = 0; i < ep->nurbs; i++) {
 			struct snd_urb_ctx *ctx = ep->urb + i;
 			list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs);
@@ -990,7 +996,7 @@ void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
 	 * and add it to the list of pending urbs. queue_pending_output_urbs()
 	 * will take care of them later.
 	 */
-	if (snd_usb_endpoint_implict_feedback_sink(ep) &&
+	if (snd_usb_endpoint_implicit_feedback_sink(ep) &&
 	    ep->use_count != 0) {
 
 		/* implicit feedback case */
diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h
index 447902dd8a4a..2287adf5ca59 100644
--- a/sound/usb/endpoint.h
+++ b/sound/usb/endpoint.h
@@ -23,7 +23,7 @@ int  snd_usb_endpoint_activate(struct snd_usb_endpoint *ep);
 int  snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep);
 void snd_usb_endpoint_free(struct list_head *head);
 
-int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep);
+int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep);
 int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep);
 
 void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
diff --git a/sound/usb/format.c b/sound/usb/format.c
index e831ee4238bb..99299ffb33ac 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -43,11 +43,11 @@
  */
 static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
 				     struct audioformat *fp,
-				     int format, void *_fmt,
+				     unsigned int format, void *_fmt,
 				     int protocol)
 {
 	int sample_width, sample_bytes;
-	u64 pcm_formats;
+	u64 pcm_formats = 0;
 
 	switch (protocol) {
 	case UAC_VERSION_1:
@@ -63,14 +63,17 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
 		struct uac_format_type_i_ext_descriptor *fmt = _fmt;
 		sample_width = fmt->bBitResolution;
 		sample_bytes = fmt->bSubslotSize;
+
+		if (format & UAC2_FORMAT_TYPE_I_RAW_DATA)
+			pcm_formats |= SNDRV_PCM_FMTBIT_SPECIAL;
+
 		format <<= 1;
 		break;
 	}
 	}
 
-	pcm_formats = 0;
-
-	if (format == 0 || format == (1 << UAC_FORMAT_TYPE_I_UNDEFINED)) {
+	if ((pcm_formats == 0) &&
+	    (format == 0 || format == (1 << UAC_FORMAT_TYPE_I_UNDEFINED))) {
 		/* some devices don't define this correctly... */
 		snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n",
 			    chip->dev->devnum, fp->iface, fp->altsetting);
@@ -133,6 +136,9 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
 		snd_printk(KERN_INFO "%d:%u:%d : unsupported format bits %#x\n",
 			   chip->dev->devnum, fp->iface, fp->altsetting, format);
 	}
+
+	pcm_formats |= snd_usb_interface_dsd_format_quirks(chip, fp, sample_bytes);
+
 	return pcm_formats;
 }
 
@@ -277,7 +283,7 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
 	struct usb_device *dev = chip->dev;
 	unsigned char tmp[2], *data;
 	int nr_triplets, data_size, ret = 0;
-	int clock = snd_usb_clock_find_source(chip, fp->clock);
+	int clock = snd_usb_clock_find_source(chip, fp->clock, false);
 
 	if (clock < 0) {
 		snd_printk(KERN_ERR "%s(): unable to find clock source (clock %d)\n",
@@ -353,13 +359,14 @@ err:
  * parse the format type I and III descriptors
  */
 static int parse_audio_format_i(struct snd_usb_audio *chip,
-				struct audioformat *fp, int format,
+				struct audioformat *fp, unsigned int format,
 				struct uac_format_type_i_continuous_descriptor *fmt,
 				struct usb_host_interface *iface)
 {
 	struct usb_interface_descriptor *altsd = get_iface_desc(iface);
 	int protocol = altsd->bInterfaceProtocol;
-	int pcm_format, ret;
+	snd_pcm_format_t pcm_format;
+	int ret;
 
 	if (fmt->bFormatType == UAC_FORMAT_TYPE_III) {
 		/* FIXME: the format type is really IECxxx
@@ -378,7 +385,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
 		default:
 			pcm_format = SNDRV_PCM_FORMAT_S16_LE;
 		}
-		fp->formats = 1uLL << pcm_format;
+		fp->formats = pcm_format_to_bits(pcm_format);
 	} else {
 		fp->formats = parse_audio_format_i_type(chip, fp, format,
 							fmt, protocol);
@@ -473,8 +480,9 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
 	return ret;
 }
 
-int snd_usb_parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp,
-			       int format, struct uac_format_type_i_continuous_descriptor *fmt,
+int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
+			       struct audioformat *fp, unsigned int format,
+			       struct uac_format_type_i_continuous_descriptor *fmt,
 			       int stream, struct usb_host_interface *iface)
 {
 	int err;
diff --git a/sound/usb/format.h b/sound/usb/format.h
index 387924f0af85..6f315226f320 100644
--- a/sound/usb/format.h
+++ b/sound/usb/format.h
@@ -2,7 +2,7 @@
 #define __USBAUDIO_FORMAT_H
 
 int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
-			       struct audioformat *fp, int format,
+			       struct audioformat *fp, unsigned int format,
 			       struct uac_format_type_i_continuous_descriptor *fmt,
 			       int stream, struct usb_host_interface *iface);
 
diff --git a/sound/usb/helper.c b/sound/usb/helper.c
index c1db28f874c2..620902463c6e 100644
--- a/sound/usb/helper.c
+++ b/sound/usb/helper.c
@@ -86,14 +86,22 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
 {
 	int err;
 	void *buf = NULL;
+	int timeout;
 
 	if (size > 0) {
 		buf = kmemdup(data, size, GFP_KERNEL);
 		if (!buf)
 			return -ENOMEM;
 	}
+
+	if (requesttype & USB_DIR_IN)
+		timeout = USB_CTRL_GET_TIMEOUT;
+	else
+		timeout = USB_CTRL_SET_TIMEOUT;
+
 	err = usb_control_msg(dev, pipe, request, requesttype,
-			      value, index, buf, size, 1000);
+			      value, index, buf, size, timeout);
+
 	if (size > 0) {
 		memcpy(data, buf, size);
 		kfree(buf);
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index 34b9bb7fe87c..8e01fa4991c5 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -126,7 +126,6 @@ struct snd_usb_midi {
 		struct snd_usb_midi_in_endpoint *in;
 	} endpoints[MIDI_MAX_ENDPOINTS];
 	unsigned long input_triggered;
-	bool autopm_reference;
 	unsigned int opened[2];
 	unsigned char disconnected;
 	unsigned char input_running;
@@ -1040,7 +1039,6 @@ static int substream_open(struct snd_rawmidi_substream *substream, int dir,
 {
 	struct snd_usb_midi* umidi = substream->rmidi->private_data;
 	struct snd_kcontrol *ctl;
-	int err;
 
 	down_read(&umidi->disc_rwsem);
 	if (umidi->disconnected) {
@@ -1051,13 +1049,6 @@ static int substream_open(struct snd_rawmidi_substream *substream, int dir,
 	mutex_lock(&umidi->mutex);
 	if (open) {
 		if (!umidi->opened[0] && !umidi->opened[1]) {
-			err = usb_autopm_get_interface(umidi->iface);
-			umidi->autopm_reference = err >= 0;
-			if (err < 0 && err != -EACCES) {
-				mutex_unlock(&umidi->mutex);
-				up_read(&umidi->disc_rwsem);
-				return -EIO;
-			}
 			if (umidi->roland_load_ctl) {
 				ctl = umidi->roland_load_ctl;
 				ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
@@ -1080,8 +1071,6 @@ static int substream_open(struct snd_rawmidi_substream *substream, int dir,
 				snd_ctl_notify(umidi->card,
 				       SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
 			}
-			if (umidi->autopm_reference)
-				usb_autopm_put_interface(umidi->iface);
 		}
 	}
 	mutex_unlock(&umidi->mutex);
@@ -1455,6 +1444,7 @@ void snd_usbmidi_disconnect(struct list_head* p)
 	}
 	del_timer_sync(&umidi->error_timer);
 }
+EXPORT_SYMBOL(snd_usbmidi_disconnect);
 
 static void snd_usbmidi_rawmidi_free(struct snd_rawmidi *rmidi)
 {
@@ -1465,10 +1455,9 @@ static void snd_usbmidi_rawmidi_free(struct snd_rawmidi *rmidi)
 static struct snd_rawmidi_substream *snd_usbmidi_find_substream(struct snd_usb_midi* umidi,
 								int stream, int number)
 {
-	struct list_head* list;
+	struct snd_rawmidi_substream *substream;
 
-	list_for_each(list, &umidi->rmidi->streams[stream].substreams) {
-		struct snd_rawmidi_substream *substream = list_entry(list, struct snd_rawmidi_substream, list);
+	list_for_each_entry(substream, &umidi->rmidi->streams[stream].substreams, list) {
 		if (substream->number == number)
 			return substream;
 	}
@@ -2091,6 +2080,7 @@ void snd_usbmidi_input_stop(struct list_head* p)
 	}
 	umidi->input_running = 0;
 }
+EXPORT_SYMBOL(snd_usbmidi_input_stop);
 
 static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep)
 {
@@ -2120,6 +2110,7 @@ void snd_usbmidi_input_start(struct list_head* p)
 		snd_usbmidi_input_start_ep(umidi->endpoints[i].in);
 	umidi->input_running = 1;
 }
+EXPORT_SYMBOL(snd_usbmidi_input_start);
 
 /*
  * Creates and registers everything needed for a MIDI streaming interface.
@@ -2256,11 +2247,9 @@ int snd_usbmidi_create(struct snd_card *card,
 		return err;
 	}
 
+	usb_autopm_get_interface_no_resume(umidi->iface);
+
 	list_add_tail(&umidi->list, midi_list);
 	return 0;
 }
-
 EXPORT_SYMBOL(snd_usbmidi_create);
-EXPORT_SYMBOL(snd_usbmidi_input_stop);
-EXPORT_SYMBOL(snd_usbmidi_input_start);
-EXPORT_SYMBOL(snd_usbmidi_disconnect);
diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c
index 8b81cb54026f..6ad617b94732 100644
--- a/sound/usb/misc/ua101.c
+++ b/sound/usb/misc/ua101.c
@@ -1120,8 +1120,7 @@ static int alloc_stream_urbs(struct ua101 *ua, struct ua101_stream *stream,
 			usb_init_urb(&urb->urb);
 			urb->urb.dev = ua->dev;
 			urb->urb.pipe = stream->usb_pipe;
-			urb->urb.transfer_flags = URB_ISO_ASAP |
-					URB_NO_TRANSFER_DMA_MAP;
+			urb->urb.transfer_flags = URB_NO_TRANSFER_DMA_MAP;
 			urb->urb.transfer_buffer = addr;
 			urb->urb.transfer_dma = dma;
 			urb->urb.transfer_buffer_length = max_packet_size;
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index f94397b42aa5..93b6e32cfead 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -16,6 +16,7 @@
 
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/bitrev.h>
 #include <linux/ratelimit.h>
 #include <linux/usb.h>
 #include <linux/usb/audio.h>
@@ -94,14 +95,12 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream
  */
 static struct audioformat *find_format(struct snd_usb_substream *subs)
 {
-	struct list_head *p;
+	struct audioformat *fp;
 	struct audioformat *found = NULL;
 	int cur_attr = 0, attr;
 
-	list_for_each(p, &subs->fmt_list) {
-		struct audioformat *fp;
-		fp = list_entry(p, struct audioformat, list);
-		if (!(fp->formats & (1uLL << subs->pcm_format)))
+	list_for_each_entry(fp, &subs->fmt_list, list) {
+		if (!(fp->formats & pcm_format_to_bits(subs->pcm_format)))
 			continue;
 		if (fp->channels != subs->channels)
 			continue;
@@ -350,6 +349,8 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
 				fmt->iface, fmt->altsetting);
 		subs->interface = fmt->iface;
 		subs->altset_idx = fmt->altset_idx;
+
+		snd_usb_set_interface_quirk(dev);
 	}
 
 	subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip,
@@ -477,7 +478,7 @@ static int match_endpoint_audioformats(struct audioformat *fp,
 		return 0;
 	}
 
-	if (!(fp->formats & (1ULL << pcm_format))) {
+	if (!(fp->formats & pcm_format_to_bits(pcm_format))) {
 		snd_printdd("%s: (fmt @%p) no match for format %d\n", __func__,
 			fp, pcm_format);
 		return 0;
@@ -802,7 +803,7 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params,
 			struct snd_pcm_hw_rule *rule)
 {
 	struct snd_usb_substream *subs = rule->private;
-	struct list_head *p;
+	struct audioformat *fp;
 	struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
 	unsigned int rmin, rmax;
 	int changed;
@@ -810,9 +811,7 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params,
 	hwc_debug("hw_rule_rate: (%d,%d)\n", it->min, it->max);
 	changed = 0;
 	rmin = rmax = 0;
-	list_for_each(p, &subs->fmt_list) {
-		struct audioformat *fp;
-		fp = list_entry(p, struct audioformat, list);
+	list_for_each_entry(fp, &subs->fmt_list, list) {
 		if (!hw_check_valid_format(subs, params, fp))
 			continue;
 		if (changed++) {
@@ -856,7 +855,7 @@ static int hw_rule_channels(struct snd_pcm_hw_params *params,
 			    struct snd_pcm_hw_rule *rule)
 {
 	struct snd_usb_substream *subs = rule->private;
-	struct list_head *p;
+	struct audioformat *fp;
 	struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
 	unsigned int rmin, rmax;
 	int changed;
@@ -864,9 +863,7 @@ static int hw_rule_channels(struct snd_pcm_hw_params *params,
 	hwc_debug("hw_rule_channels: (%d,%d)\n", it->min, it->max);
 	changed = 0;
 	rmin = rmax = 0;
-	list_for_each(p, &subs->fmt_list) {
-		struct audioformat *fp;
-		fp = list_entry(p, struct audioformat, list);
+	list_for_each_entry(fp, &subs->fmt_list, list) {
 		if (!hw_check_valid_format(subs, params, fp))
 			continue;
 		if (changed++) {
@@ -909,7 +906,7 @@ static int hw_rule_format(struct snd_pcm_hw_params *params,
 			  struct snd_pcm_hw_rule *rule)
 {
 	struct snd_usb_substream *subs = rule->private;
-	struct list_head *p;
+	struct audioformat *fp;
 	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
 	u64 fbits;
 	u32 oldbits[2];
@@ -917,9 +914,7 @@ static int hw_rule_format(struct snd_pcm_hw_params *params,
 
 	hwc_debug("hw_rule_format: %x:%x\n", fmt->bits[0], fmt->bits[1]);
 	fbits = 0;
-	list_for_each(p, &subs->fmt_list) {
-		struct audioformat *fp;
-		fp = list_entry(p, struct audioformat, list);
+	list_for_each_entry(fp, &subs->fmt_list, list) {
 		if (!hw_check_valid_format(subs, params, fp))
 			continue;
 		fbits |= fp->formats;
@@ -1027,7 +1022,7 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,
 
 static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substream *subs)
 {
-	struct list_head *p;
+	struct audioformat *fp;
 	unsigned int pt, ptmin;
 	int param_period_time_if_needed;
 	int err;
@@ -1041,9 +1036,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
 	runtime->hw.rates = 0;
 	ptmin = UINT_MAX;
 	/* check min/max rates and channels */
-	list_for_each(p, &subs->fmt_list) {
-		struct audioformat *fp;
-		fp = list_entry(p, struct audioformat, list);
+	list_for_each_entry(fp, &subs->fmt_list, list) {
 		runtime->hw.rates |= fp->rates;
 		if (runtime->hw.rate_min > fp->rate_min)
 			runtime->hw.rate_min = fp->rate_min;
@@ -1128,6 +1121,12 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction)
 	runtime->private_data = subs;
 	subs->pcm_substream = substream;
 	/* runtime PM is also done there */
+
+	/* initialize DSD/DOP context */
+	subs->dsd_dop.byte_idx = 0;
+	subs->dsd_dop.channel = 0;
+	subs->dsd_dop.marker = 1;
+
 	return setup_hw_info(runtime, subs);
 }
 
@@ -1170,7 +1169,7 @@ static void retire_capture_urb(struct snd_usb_substream *subs,
 	stride = runtime->frame_bits >> 3;
 
 	for (i = 0; i < urb->number_of_packets; i++) {
-		cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+		cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset + subs->pkt_offset_adj;
 		if (urb->iso_frame_desc[i].status && printk_ratelimit()) {
 			snd_printdd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status);
 			// continue;
@@ -1222,6 +1221,61 @@ static void retire_capture_urb(struct snd_usb_substream *subs,
 		snd_pcm_period_elapsed(subs->pcm_substream);
 }
 
+static inline void fill_playback_urb_dsd_dop(struct snd_usb_substream *subs,
+					     struct urb *urb, unsigned int bytes)
+{
+	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
+	unsigned int stride = runtime->frame_bits >> 3;
+	unsigned int dst_idx = 0;
+	unsigned int src_idx = subs->hwptr_done;
+	unsigned int wrap = runtime->buffer_size * stride;
+	u8 *dst = urb->transfer_buffer;
+	u8 *src = runtime->dma_area;
+	u8 marker[] = { 0x05, 0xfa };
+
+	/*
+	 * The DSP DOP format defines a way to transport DSD samples over
+	 * normal PCM data endpoints. It requires stuffing of marker bytes
+	 * (0x05 and 0xfa, alternating per sample frame), and then expects
+	 * 2 additional bytes of actual payload. The whole frame is stored
+	 * LSB.
+	 *
+	 * Hence, for a stereo transport, the buffer layout looks like this,
+	 * where L refers to left channel samples and R to right.
+	 *
+	 *   L1 L2 0x05   R1 R2 0x05   L3 L4 0xfa  R3 R4 0xfa
+	 *   L5 L6 0x05   R5 R6 0x05   L7 L8 0xfa  R7 R8 0xfa
+	 *   .....
+	 *
+	 */
+
+	while (bytes--) {
+		if (++subs->dsd_dop.byte_idx == 3) {
+			/* frame boundary? */
+			dst[dst_idx++] = marker[subs->dsd_dop.marker];
+			src_idx += 2;
+			subs->dsd_dop.byte_idx = 0;
+
+			if (++subs->dsd_dop.channel % runtime->channels == 0) {
+				/* alternate the marker */
+				subs->dsd_dop.marker++;
+				subs->dsd_dop.marker %= ARRAY_SIZE(marker);
+				subs->dsd_dop.channel = 0;
+			}
+		} else {
+			/* stuff the DSD payload */
+			int idx = (src_idx + subs->dsd_dop.byte_idx - 1) % wrap;
+
+			if (subs->cur_audiofmt->dsd_bitrev)
+				dst[dst_idx++] = bitrev8(src[idx]);
+			else
+				dst[dst_idx++] = src[idx];
+
+			subs->hwptr_done++;
+		}
+	}
+}
+
 static void prepare_playback_urb(struct snd_usb_substream *subs,
 				 struct urb *urb)
 {
@@ -1244,8 +1298,8 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
 			counts = snd_usb_endpoint_next_packet_size(ep);
 
 		/* set up descriptor */
-		urb->iso_frame_desc[i].offset = frames * stride;
-		urb->iso_frame_desc[i].length = counts * stride;
+		urb->iso_frame_desc[i].offset = frames * ep->stride;
+		urb->iso_frame_desc[i].length = counts * ep->stride;
 		frames += counts;
 		urb->number_of_packets++;
 		subs->transfer_done += counts;
@@ -1259,14 +1313,14 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
 					frames -= subs->transfer_done;
 					counts -= subs->transfer_done;
 					urb->iso_frame_desc[i].length =
-						counts * stride;
+						counts * ep->stride;
 					subs->transfer_done = 0;
 				}
 				i++;
 				if (i < ctx->packets) {
 					/* add a transfer delimiter */
 					urb->iso_frame_desc[i].offset =
-						frames * stride;
+						frames * ep->stride;
 					urb->iso_frame_desc[i].length = 0;
 					urb->number_of_packets++;
 				}
@@ -1274,23 +1328,43 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
 			}
 		}
 		if (period_elapsed &&
-		    !snd_usb_endpoint_implict_feedback_sink(subs->data_endpoint)) /* finish at the period boundary */
+		    !snd_usb_endpoint_implicit_feedback_sink(subs->data_endpoint)) /* finish at the period boundary */
 			break;
 	}
-	bytes = frames * stride;
-	if (subs->hwptr_done + bytes > runtime->buffer_size * stride) {
-		/* err, the transferred area goes over buffer boundary. */
-		unsigned int bytes1 =
-			runtime->buffer_size * stride - subs->hwptr_done;
-		memcpy(urb->transfer_buffer,
-		       runtime->dma_area + subs->hwptr_done, bytes1);
-		memcpy(urb->transfer_buffer + bytes1,
-		       runtime->dma_area, bytes - bytes1);
+	bytes = frames * ep->stride;
+
+	if (unlikely(subs->pcm_format == SNDRV_PCM_FORMAT_DSD_U16_LE &&
+		     subs->cur_audiofmt->dsd_dop)) {
+		fill_playback_urb_dsd_dop(subs, urb, bytes);
+	} else if (unlikely(subs->pcm_format == SNDRV_PCM_FORMAT_DSD_U8 &&
+			   subs->cur_audiofmt->dsd_bitrev)) {
+		/* bit-reverse the bytes */
+		u8 *buf = urb->transfer_buffer;
+		for (i = 0; i < bytes; i++) {
+			int idx = (subs->hwptr_done + i)
+				% (runtime->buffer_size * stride);
+			buf[i] = bitrev8(runtime->dma_area[idx]);
+		}
+
+		subs->hwptr_done += bytes;
 	} else {
-		memcpy(urb->transfer_buffer,
-		       runtime->dma_area + subs->hwptr_done, bytes);
+		/* usual PCM */
+		if (subs->hwptr_done + bytes > runtime->buffer_size * stride) {
+			/* err, the transferred area goes over buffer boundary. */
+			unsigned int bytes1 =
+				runtime->buffer_size * stride - subs->hwptr_done;
+			memcpy(urb->transfer_buffer,
+			       runtime->dma_area + subs->hwptr_done, bytes1);
+			memcpy(urb->transfer_buffer + bytes1,
+			       runtime->dma_area, bytes - bytes1);
+		} else {
+			memcpy(urb->transfer_buffer,
+			       runtime->dma_area + subs->hwptr_done, bytes);
+		}
+
+		subs->hwptr_done += bytes;
 	}
-	subs->hwptr_done += bytes;
+
 	if (subs->hwptr_done >= runtime->buffer_size * stride)
 		subs->hwptr_done -= runtime->buffer_size * stride;
 
@@ -1318,8 +1392,8 @@ static void retire_playback_urb(struct snd_usb_substream *subs,
 {
 	unsigned long flags;
 	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
-	int stride = runtime->frame_bits >> 3;
-	int processed = urb->transfer_buffer_length / stride;
+	struct snd_usb_endpoint *ep = subs->data_endpoint;
+	int processed = urb->transfer_buffer_length / ep->stride;
 	int est_delay;
 
 	/* ignore the delay accounting when procssed=0 is given, i.e.
diff --git a/sound/usb/proc.c b/sound/usb/proc.c
index d218f763501f..135c76871063 100644
--- a/sound/usb/proc.c
+++ b/sound/usb/proc.c
@@ -73,20 +73,19 @@ void snd_usb_audio_create_proc(struct snd_usb_audio *chip)
  */
 static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct snd_info_buffer *buffer)
 {
-	struct list_head *p;
+	struct audioformat *fp;
 	static char *sync_types[4] = {
 		"NONE", "ASYNC", "ADAPTIVE", "SYNC"
 	};
 
-	list_for_each(p, &subs->fmt_list) {
-		struct audioformat *fp;
+	list_for_each_entry(fp, &subs->fmt_list, list) {
 		snd_pcm_format_t fmt;
-		fp = list_entry(p, struct audioformat, list);
+
 		snd_iprintf(buffer, "  Interface %d\n", fp->iface);
 		snd_iprintf(buffer, "    Altset %d\n", fp->altsetting);
 		snd_iprintf(buffer, "    Format:");
 		for (fmt = 0; fmt <= SNDRV_PCM_FORMAT_LAST; ++fmt)
-			if (fp->formats & (1uLL << fmt))
+			if (fp->formats & pcm_format_to_bits(fmt))
 				snd_iprintf(buffer, " %s",
 					    snd_pcm_format_name(fmt));
 		snd_iprintf(buffer, "\n");
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index c39f898b15d2..7f1722f82c89 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -353,6 +353,84 @@ YAMAHA_DEVICE(0x105d, NULL),
 		}
 	}
 },
+{
+	USB_DEVICE(0x0499, 0x1507),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		/* .vendor_name = "Yamaha", */
+		/* .product_name = "THR10", */
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = (const struct snd_usb_audio_quirk[]) {
+			{
+				.ifnum = 1,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 2,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 3,
+				.type = QUIRK_MIDI_YAMAHA
+			},
+			{
+				.ifnum = -1
+			}
+		}
+	}
+},
+{
+	USB_DEVICE(0x0499, 0x150a),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		/* .vendor_name = "Yamaha", */
+		/* .product_name = "THR5A", */
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = (const struct snd_usb_audio_quirk[]) {
+			{
+				.ifnum = 1,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 2,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 3,
+				.type = QUIRK_MIDI_YAMAHA
+			},
+			{
+				.ifnum = -1
+			}
+		}
+	}
+},
+{
+	USB_DEVICE(0x0499, 0x150c),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		/* .vendor_name = "Yamaha", */
+		/* .product_name = "THR10C", */
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = (const struct snd_usb_audio_quirk[]) {
+			{
+				.ifnum = 1,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 2,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 3,
+				.type = QUIRK_MIDI_YAMAHA
+			},
+			{
+				.ifnum = -1
+			}
+		}
+	}
+},
 YAMAHA_DEVICE(0x2000, "DGP-7"),
 YAMAHA_DEVICE(0x2001, "DGP-5"),
 YAMAHA_DEVICE(0x2002, NULL),
@@ -2748,6 +2826,46 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 	}
 },
 {
+	USB_DEVICE(0x1235, 0x0018),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.vendor_name = "Novation",
+		.product_name = "Twitch",
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = (const struct snd_usb_audio_quirk[]) {
+			{
+				.ifnum = 0,
+				.type = QUIRK_AUDIO_FIXED_ENDPOINT,
+				.data = & (const struct audioformat) {
+					.formats = SNDRV_PCM_FMTBIT_S24_3LE,
+					.channels = 4,
+					.iface = 0,
+					.altsetting = 1,
+					.altset_idx = 1,
+					.attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+					.endpoint = 0x01,
+					.ep_attr = USB_ENDPOINT_XFER_ISOC,
+					.rates = SNDRV_PCM_RATE_44100 |
+						 SNDRV_PCM_RATE_48000,
+					.rate_min = 44100,
+					.rate_max = 48000,
+					.nr_rates = 2,
+					.rate_table = (unsigned int[]) {
+						44100, 48000
+					}
+				}
+			},
+			{
+				.ifnum = 1,
+				.type = QUIRK_MIDI_RAW_BYTES
+			},
+			{
+				.ifnum = -1
+			}
+		}
+	}
+},
+{
 	USB_DEVICE_VENDOR_SPEC(0x1235, 0x4661),
 	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
 		.vendor_name = "Novation",
@@ -2996,7 +3114,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 					.attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
 					.endpoint = 0x02,
 					.ep_attr = 0x01,
-					.maxpacksize = 0x130,
 					.rates = SNDRV_PCM_RATE_44100 |
 						 SNDRV_PCM_RATE_48000,
 					.rate_min = 44100,
@@ -3044,7 +3161,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 					.attributes = 0x00,
 					.endpoint = 0x03,
 					.ep_attr = USB_ENDPOINT_SYNC_ASYNC,
-					.maxpacksize = 0x128,
 					.rates = SNDRV_PCM_RATE_48000,
 					.rate_min = 48000,
 					.rate_max = 48000,
@@ -3070,7 +3186,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 					.attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
 					.endpoint = 0x85,
 					.ep_attr = USB_ENDPOINT_SYNC_SYNC,
-					.maxpacksize = 0x128,
 					.rates = SNDRV_PCM_RATE_48000,
 					.rate_min = 48000,
 					.rate_max = 48000,
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 9c5ab22358b1..3879eae7e874 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -165,8 +165,10 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
 		return -EINVAL;
 	}
 	alts = &iface->altsetting[fp->altset_idx];
-	fp->datainterval = snd_usb_parse_datainterval(chip, alts);
-	fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
+	if (fp->datainterval == 0)
+		fp->datainterval = snd_usb_parse_datainterval(chip, alts);
+	if (fp->maxpacksize == 0)
+		fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
 	usb_set_interface(chip->dev, fp->iface, 0);
 	snd_usb_init_pitch(chip, fp->iface, alts, fp);
 	snd_usb_init_sample_rate(chip, fp->iface, alts, fp, fp->rate_max);
@@ -446,6 +448,17 @@ static int snd_usb_cm6206_boot_quirk(struct usb_device *dev)
 }
 
 /*
+ * Novation Twitch DJ controller
+ */
+static int snd_usb_twitch_boot_quirk(struct usb_device *dev)
+{
+	/* preemptively set up the device because otherwise the
+	 * raw MIDI endpoints are not active */
+	usb_set_interface(dev, 0, 1);
+	return 0;
+}
+
+/*
  * This call will put the synth in "USB send" mode, i.e it will send MIDI
  * messages through USB (this is disabled at startup). The synth will
  * acknowledge by sending a sysex on endpoint 0x85 and by displaying a USB
@@ -746,6 +759,10 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,
 		/* Digidesign Mbox 2 */
 		return snd_usb_mbox2_boot_quirk(dev);
 
+	case USB_ID(0x1235, 0x0018):
+		/* Focusrite Novation Twitch */
+		return snd_usb_twitch_boot_quirk(dev);
+
 	case USB_ID(0x133e, 0x0815):
 		/* Access Music VirusTI Desktop */
 		return snd_usb_accessmusic_boot_quirk(dev);
@@ -837,6 +854,7 @@ static void set_format_emu_quirk(struct snd_usb_substream *subs,
 		break;
 	}
 	snd_emuusb_set_samplerate(subs->stream->chip, emu_samplerate_id);
+	subs->pkt_offset_adj = (emu_samplerate_id >= EMU_QUIRK_SR_176400HZ) ? 4 : 0;
 }
 
 void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
@@ -875,6 +893,16 @@ void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep)
 		ep->skip_packets = 16;
 }
 
+void snd_usb_set_interface_quirk(struct usb_device *dev)
+{
+	/*
+	 * "Playback Design" products need a 50ms delay after setting the
+	 * USB interface.
+	 */
+	if (le16_to_cpu(dev->descriptor.idVendor) == 0x23ba)
+		mdelay(50);
+}
+
 void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
 			   __u8 request, __u8 requesttype, __u16 value,
 			   __u16 index, void *data, __u16 size)
@@ -888,3 +916,31 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
 		mdelay(20);
 }
 
+/*
+ * snd_usb_interface_dsd_format_quirks() is called from format.c to
+ * augment the PCM format bit-field for DSD types. The UAC standards
+ * don't have a designated bit field to denote DSD-capable interfaces,
+ * hence all hardware that is known to support this format has to be
+ * listed here.
+ */
+u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
+					struct audioformat *fp,
+					unsigned int sample_bytes)
+{
+	/* Playback Designs */
+	if (le16_to_cpu(chip->dev->descriptor.idVendor) == 0x23ba) {
+		switch (fp->altsetting) {
+		case 1:
+			fp->dsd_dop = true;
+			return SNDRV_PCM_FMTBIT_DSD_U16_LE;
+		case 2:
+			fp->dsd_bitrev = true;
+			return SNDRV_PCM_FMTBIT_DSD_U8;
+		case 3:
+			fp->dsd_bitrev = true;
+			return SNDRV_PCM_FMTBIT_DSD_U16_LE;
+		}
+	}
+
+	return 0;
+}
diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h
index 0ca9e91067a6..665e972a1b40 100644
--- a/sound/usb/quirks.h
+++ b/sound/usb/quirks.h
@@ -26,8 +26,13 @@ int snd_usb_is_big_endian_format(struct snd_usb_audio *chip,
 
 void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep);
 
+void snd_usb_set_interface_quirk(struct usb_device *dev);
 void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
 			   __u8 request, __u8 requesttype, __u16 value,
 			   __u16 index, void *data, __u16 size);
 
+u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
+					struct audioformat *fp,
+					unsigned int sample_bytes);
+
 #endif /* __USBAUDIO_QUIRKS_H */
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index ad181d538bd9..7db2f8958e79 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -42,12 +42,11 @@
  */
 static void free_substream(struct snd_usb_substream *subs)
 {
-	struct list_head *p, *n;
+	struct audioformat *fp, *n;
 
 	if (!subs->num_formats)
 		return; /* not initialized */
-	list_for_each_safe(p, n, &subs->fmt_list) {
-		struct audioformat *fp = list_entry(p, struct audioformat, list);
+	list_for_each_entry_safe(fp, n, &subs->fmt_list, list) {
 		kfree(fp->rate_table);
 		kfree(fp->chmap);
 		kfree(fp);
@@ -94,6 +93,7 @@ static void snd_usb_init_substream(struct snd_usb_stream *as,
 	subs->dev = as->chip->dev;
 	subs->txfr_quirk = as->chip->txfr_quirk;
 	subs->speed = snd_usb_get_speed(subs->dev);
+	subs->pkt_offset_adj = 0;
 
 	snd_usb_set_pcm_ops(as->pcm, stream);
 
@@ -313,14 +313,12 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
 			     int stream,
 			     struct audioformat *fp)
 {
-	struct list_head *p;
 	struct snd_usb_stream *as;
 	struct snd_usb_substream *subs;
 	struct snd_pcm *pcm;
 	int err;
 
-	list_for_each(p, &chip->pcm_list) {
-		as = list_entry(p, struct snd_usb_stream, list);
+	list_for_each_entry(as, &chip->pcm_list, list) {
 		if (as->fmt_type != fp->fmt_type)
 			continue;
 		subs = &as->substream[stream];
@@ -332,8 +330,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
 		}
 	}
 	/* look for an empty stream */
-	list_for_each(p, &chip->pcm_list) {
-		as = list_entry(p, struct snd_usb_stream, list);
+	list_for_each_entry(as, &chip->pcm_list, list) {
 		if (as->fmt_type != fp->fmt_type)
 			continue;
 		subs = &as->substream[stream];
@@ -396,6 +393,14 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
 	if (!csep && altsd->bNumEndpoints >= 2)
 		csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT);
 
+	/*
+	 * If we can't locate the USB_DT_CS_ENDPOINT descriptor in the extra
+	 * bytes after the first endpoint, go search the entire interface.
+	 * Some devices have it directly *before* the standard endpoint.
+	 */
+	if (!csep)
+		csep = snd_usb_find_desc(alts->extra, alts->extralen, NULL, USB_DT_CS_ENDPOINT);
+
 	if (!csep || csep->bLength < 7 ||
 	    csep->bDescriptorSubtype != UAC_EP_GENERAL) {
 		snd_printk(KERN_WARNING "%d:%u:%d : no or invalid"
@@ -463,7 +468,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
 	struct usb_host_interface *alts;
 	struct usb_interface_descriptor *altsd;
 	int i, altno, err, stream;
-	int format = 0, num_channels = 0;
+	unsigned int format = 0, num_channels = 0;
 	struct audioformat *fp = NULL;
 	int num, protocol, clock = 0;
 	struct uac_format_type_i_continuous_descriptor *fmt;
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 1ac3fd9cc5a6..bc43bcaddf4d 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -56,6 +56,7 @@ struct snd_usb_audio {
 
 	int setup;			/* from the 'device_setup' module param */
 	int nrpacks;			/* from the 'nrpacks' module param */
+	bool autoclock;			/* from the 'autoclock' module param */
 
 	struct usb_host_interface *ctrl_intf;	/* the audio control interface */
 };
diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c
index 1e7a47a86605..bf618e1500ac 100644
--- a/sound/usb/usx2y/usb_stream.c
+++ b/sound/usb/usx2y/usb_stream.c
@@ -69,7 +69,6 @@ static void init_pipe_urbs(struct usb_stream_kernel *sk, unsigned use_packsize,
 	     ++u, transfer += transfer_length) {
 		struct urb *urb = urbs[u];
 		struct usb_iso_packet_descriptor *desc;
-		urb->transfer_flags = URB_ISO_ASAP;
 		urb->transfer_buffer = transfer;
 		urb->dev = dev;
 		urb->pipe = pipe;
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index 520ef96d7c75..b37653247ef4 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -503,7 +503,6 @@ static int usX2Y_urbs_start(struct snd_usX2Y_substream *subs)
 			if (0 == i)
 				atomic_set(&subs->state, state_STARTING3);
 			urb->dev = usX2Y->dev;
-			urb->transfer_flags = URB_ISO_ASAP;
 			for (pack = 0; pack < nr_of_packs(); pack++) {
 				urb->iso_frame_desc[pack].offset = subs->maxpacksize * pack;
 				urb->iso_frame_desc[pack].length = subs->maxpacksize;
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c
index cc56007791e0..f2a1acdc4d83 100644
--- a/sound/usb/usx2y/usx2yhwdeppcm.c
+++ b/sound/usb/usx2y/usx2yhwdeppcm.c
@@ -443,7 +443,6 @@ static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs)
 					if (0 == u)
 						atomic_set(&subs->state, state_STARTING3);
 					urb->dev = usX2Y->dev;
-					urb->transfer_flags = URB_ISO_ASAP;
 					for (pack = 0; pack < nr_of_packs(); pack++) {
 						urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs());
 						urb->iso_frame_desc[pack].length = subs->maxpacksize;