Merge branch 'topic/seq-autoload' into for-next
diff --git a/Documentation/DocBook/writing-an-alsa-driver.tmpl b/Documentation/DocBook/writing-an-alsa-driver.tmpl
index 6f639d9..784793d 100644
--- a/Documentation/DocBook/writing-an-alsa-driver.tmpl
+++ b/Documentation/DocBook/writing-an-alsa-driver.tmpl
@@ -2742,7 +2742,9 @@
 
         <para>
           Another note is that this callback is non-atomic
-        (schedulable). This is important, because the
+        (schedulable) as default, i.e. when no
+	<structfield>nonatomic</structfield> flag set.
+	This is important, because the
         <structfield>trigger</structfield> callback 
         is atomic (non-schedulable). That is, mutexes or any
         schedule-related functions are not available in
@@ -2900,8 +2902,9 @@
         </para>
 
         <para>
-          As mentioned, this callback is atomic.  You cannot call
-	  functions which may sleep.
+          As mentioned, this callback is atomic as default unless
+	  <structfield>nonatomic</structfield> flag set, and
+	  you cannot call functions which may sleep.
 	  The trigger callback should be as minimal as possible,
 	  just really triggering the DMA.  The other stuff should be
 	  initialized hw_params and prepare callbacks properly
@@ -2936,7 +2939,7 @@
         </para>
 
         <para>
-          This callback is also atomic.
+          This callback is also atomic as default.
         </para>
       </section>
 
@@ -2972,7 +2975,7 @@
 	is useful only for such a purpose.
 	</para>
 	<para>
-	  This callback is atomic.
+	  This callback is atomic as default.
 	</para>
       </section>
 
@@ -3175,6 +3178,21 @@
       called with local interrupts disabled.
       </para>
 
+      <para>
+      The recent changes in PCM core code, however, allow all PCM
+      operations to be non-atomic.  This assumes that the all caller
+      sides are in non-atomic contexts.  For example, the function
+      <function>snd_pcm_period_elapsed()</function> is called
+      typically from the interrupt handler.  But, if you set up the
+      driver to use a threaded interrupt handler, this call can be in
+      non-atomic context, too.  In such a case, you can set
+      <structfield>nonatomic</structfield> filed of
+      <structname>snd_pcm</structname> object after creating it.
+      When this flag is set, mutex and rwsem are used internally in
+      the PCM core instead of spin and rwlocks, so that you can call
+      all PCM functions safely in a non-atomic context.
+      </para>
+
     </section>
     <section id="pcm-interface-constraints">
       <title>Constraints</title>
diff --git a/Documentation/devicetree/bindings/regmap/regmap.txt b/Documentation/devicetree/bindings/regmap/regmap.txt
new file mode 100644
index 0000000..b494f8b
--- /dev/null
+++ b/Documentation/devicetree/bindings/regmap/regmap.txt
@@ -0,0 +1,47 @@
+Device-Tree binding for regmap
+
+The endianness mode of CPU & Device scenarios:
+Index     Device     Endianness properties
+---------------------------------------------------
+1         BE         'big-endian'
+2         LE         'little-endian'
+
+For one device driver, which will run in different scenarios above
+on different SoCs using the devicetree, we need one way to simplify
+this.
+
+Required properties:
+- {big,little}-endian: these are boolean properties, if absent
+  meaning that the CPU and the Device are in the same endianness mode,
+  these properties are for register values and all the buffers only.
+
+Examples:
+Scenario 1 : CPU in LE mode & device in LE mode.
+dev: dev@40031000 {
+	      compatible = "name";
+	      reg = <0x40031000 0x1000>;
+	      ...
+};
+
+Scenario 2 : CPU in LE mode & device in BE mode.
+dev: dev@40031000 {
+	      compatible = "name";
+	      reg = <0x40031000 0x1000>;
+	      ...
+	      big-endian;
+};
+
+Scenario 3 : CPU in BE mode & device in BE mode.
+dev: dev@40031000 {
+	      compatible = "name";
+	      reg = <0x40031000 0x1000>;
+	      ...
+};
+
+Scenario 4 : CPU in BE mode & device in LE mode.
+dev: dev@40031000 {
+	      compatible = "name";
+	      reg = <0x40031000 0x1000>;
+	      ...
+	      little-endian;
+};
diff --git a/Documentation/devicetree/bindings/sound/adi,ssm2602.txt b/Documentation/devicetree/bindings/sound/adi,ssm2602.txt
new file mode 100644
index 0000000..3b3302f
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/adi,ssm2602.txt
@@ -0,0 +1,19 @@
+Analog Devices SSM2602, SSM2603 and SSM2604 I2S audio CODEC devices
+
+SSM2602 support both I2C and SPI as the configuration interface,
+the selection is made by the MODE strap-in pin.
+SSM2603 and SSM2604 only support I2C as the configuration interface.
+
+Required properties:
+
+  - compatible : One of "adi,ssm2602", "adi,ssm2603" or "adi,ssm2604"
+
+  - reg : the I2C address of the device for I2C, the chip select
+          number for SPI.
+
+ Example:
+
+	ssm2602: ssm2602@1a {
+		compatible = "adi,ssm2602";
+		reg = <0x1a>;
+	};
diff --git a/Documentation/devicetree/bindings/sound/cs35l32.txt b/Documentation/devicetree/bindings/sound/cs35l32.txt
new file mode 100644
index 0000000..1417d3f
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/cs35l32.txt
@@ -0,0 +1,62 @@
+CS35L32 audio CODEC
+
+Required properties:
+
+  - compatible : "cirrus,cs35l32"
+
+  - reg : the I2C address of the device for I2C. Address is determined by the level
+  of the AD0 pin. Level 0 is 0x40 while Level 1 is 0x41.
+
+  - VA-supply, VP-supply : power supplies for the device,
+  as covered in Documentation/devicetree/bindings/regulator/regulator.txt.
+
+Optional properties:
+
+  - reset-gpios : a GPIO spec for the reset pin. If specified, it will be
+  deasserted before communication to the codec starts.
+
+  - cirrus,boost-manager : Boost voltage control.
+  0 = Automatically managed.  Boost-converter output voltage is the higher
+  of the two: Class G or adaptive LED voltage.
+  1 = Automatically managed irrespective of audio, adapting for low-power
+  dissipation when LEDs are ON, and operating in Fixed-Boost Bypass Mode
+  if LEDs are OFF (VBST = VP).
+  2 = (Default) Boost voltage fixed in Bypass Mode (VBST = VP).
+  3 = Boost voltage fixed at 5 V.
+
+  - cirrus,sdout-datacfg : Data configuration for dual CS35L32 applications only.
+  Determines the data packed in a two-CS35L32 configuration.
+  0 = Left/right channels VMON[11:0], IMON[11:0], VPMON[7:0].
+  1 = Left/right channels VMON[11:0], IMON[11:0], STATUS.
+  2 = (Default) left/right channels VMON[15:0], IMON [15:0].
+  3 = Left/right channels VPMON[7:0], STATUS.
+
+  - cirrus,sdout-share : SDOUT sharing. Determines whether one or two CS35L32
+  devices are on board sharing SDOUT.
+  0 = (Default) One IC.
+  1 = Two IC's.
+
+  - cirrus,battery-recovery : Low battery nominal recovery threshold, rising VP.
+  0 = 3.1V
+  1 = 3.2V
+  2 = 3.3V (Default)
+  3 = 3.4V
+
+  - cirrus,battery-threshold : Low battery nominal threshold, falling VP.
+  0 = 3.1V
+  1 = 3.2V
+  2 = 3.3V
+  3 = 3.4V (Default)
+  4 = 3.5V
+  5 = 3.6V
+
+Example:
+
+codec: codec@40 {
+	compatible = "cirrus,cs35l32";
+	reg = <0x40>;
+	reset-gpios = <&gpio 10 0>;
+	cirrus,boost-manager = <0x03>;
+	cirrus,sdout-datacfg = <0x02>;
+	VA-supply = <&reg_audio>;
+};
diff --git a/Documentation/devicetree/bindings/sound/es8328.txt b/Documentation/devicetree/bindings/sound/es8328.txt
new file mode 100644
index 0000000..30ea8a3
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/es8328.txt
@@ -0,0 +1,38 @@
+Everest ES8328 audio CODEC
+
+This device supports both I2C and SPI.
+
+Required properties:
+
+  - compatible : "everest,es8328"
+  - DVDD-supply : Regulator providing digital core supply voltage 1.8 - 3.6V
+  - AVDD-supply : Regulator providing analog supply voltage 3.3V
+  - PVDD-supply : Regulator providing digital IO supply voltage 1.8 - 3.6V
+  - IPVDD-supply : Regulator providing analog output voltage 3.3V
+  - clocks : A 22.5792 or 11.2896 MHz clock
+  - reg : the I2C address of the device for I2C, the chip select number for SPI
+
+Pins on the device (for linking into audio routes):
+
+  * LOUT1
+  * LOUT2
+  * ROUT1
+  * ROUT2
+  * LINPUT1
+  * RINPUT1
+  * LINPUT2
+  * RINPUT2
+  * Mic Bias
+
+
+Example:
+
+codec: es8328@11 {
+	compatible = "everest,es8328";
+	DVDD-supply = <&reg_3p3v>;
+	AVDD-supply = <&reg_3p3v>;
+	PVDD-supply = <&reg_3p3v>;
+	HPVDD-supply = <&reg_3p3v>;
+	clocks = <&clks 169>;
+	reg = <0x11>;
+};
diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.txt b/Documentation/devicetree/bindings/sound/fsl,esai.txt
index aeb8c4a..52f5b6b 100644
--- a/Documentation/devicetree/bindings/sound/fsl,esai.txt
+++ b/Documentation/devicetree/bindings/sound/fsl,esai.txt
@@ -7,7 +7,8 @@
 
 Required properties:
 
-  - compatible : Compatible list, must contain "fsl,imx35-esai".
+  - compatible : Compatible list, must contain "fsl,imx35-esai" or
+		 "fsl,vf610-esai"
 
   - reg : Offset and length of the register set for the device.
 
diff --git a/Documentation/devicetree/bindings/sound/fsl,ssi.txt b/Documentation/devicetree/bindings/sound/fsl,ssi.txt
index 3aa4a8f..5b76be4 100644
--- a/Documentation/devicetree/bindings/sound/fsl,ssi.txt
+++ b/Documentation/devicetree/bindings/sound/fsl,ssi.txt
@@ -58,13 +58,7 @@
 		    Documentation/devicetree/bindings/dma/dma.txt.
 - dma-names:	    Two dmas have to be defined, "tx" and "rx", if fsl,imx-fiq
 		    is not defined.
-- fsl,mode:         The operating mode for the SSI interface.
-                    "i2s-slave" - I2S mode, SSI is clock slave
-                    "i2s-master" - I2S mode, SSI is clock master
-                    "lj-slave" - left-justified mode, SSI is clock slave
-                    "lj-master" - l.j. mode, SSI is clock master
-                    "rj-slave" - right-justified mode, SSI is clock slave
-                    "rj-master" - r.j., SSI is clock master
+- fsl,mode:         The operating mode for the AC97 interface only.
                     "ac97-slave" - AC97 mode, SSI is clock slave
                     "ac97-master" - AC97 mode, SSI is clock master
 
diff --git a/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt b/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt
new file mode 100644
index 0000000..a96774c
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt
@@ -0,0 +1,82 @@
+Freescale Generic ASoC Sound Card with ASRC support
+
+The Freescale Generic ASoC Sound Card can be used, ideally, for all Freescale
+SoCs connecting with external CODECs.
+
+The idea of this generic sound card is a bit like ASoC Simple Card. However,
+for Freescale SoCs (especially those released in recent years), most of them
+have ASRC (Documentation/devicetree/bindings/sound/fsl,asrc.txt) inside. And
+this is a specific feature that might be painstakingly controlled and merged
+into the Simple Card.
+
+So having this generic sound card allows all Freescale SoC users to benefit
+from the simplification of a new card support and the capability of the wide
+sample rates support through ASRC.
+
+Note: The card is initially designed for those sound cards who use I2S and
+      PCM DAI formats. However, it'll be also possible to support those non
+      I2S/PCM type sound cards, such as S/PDIF audio and HDMI audio, as long
+      as the driver has been properly upgraded.
+
+
+The compatible list for this generic sound card currently:
+ "fsl,imx-audio-cs42888"
+
+ "fsl,imx-audio-wm8962"
+ (compatible with Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt)
+
+ "fsl,imx-audio-sgtl5000"
+ (compatible with Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt)
+
+Required properties:
+
+  - compatible		: Contains one of entries in the compatible list.
+
+  - model		: The user-visible name of this sound complex
+
+  - audio-cpu		: The phandle of an CPU DAI controller
+
+  - audio-codec		: The phandle of an audio codec
+
+  - audio-routing	: A list of the connections between audio components.
+			  Each entry is a pair of strings, the first being the
+			  connection's sink, the second being the connection's
+			  source. There're a few pre-designed board connectors:
+			   * Line Out Jack
+			   * Line In Jack
+			   * Headphone Jack
+			   * Mic Jack
+			   * Ext Spk
+			   * AMIC (stands for Analog Microphone Jack)
+			   * DMIC (stands for Digital Microphone Jack)
+
+			  Note: The "Mic Jack" and "AMIC" are redundant while
+			        coexsiting in order to support the old bindings
+				of wm8962 and sgtl5000.
+
+Optional properties:
+
+  - audio-asrc		: The phandle of ASRC. It can be absent if there's no
+			  need to add ASRC support via DPCM.
+
+Example:
+sound-cs42888 {
+	compatible = "fsl,imx-audio-cs42888";
+	model = "cs42888-audio";
+	audio-cpu = <&esai>;
+	audio-asrc = <&asrc>;
+	audio-codec = <&cs42888>;
+	audio-routing =
+		"Line Out Jack", "AOUT1L",
+		"Line Out Jack", "AOUT1R",
+		"Line Out Jack", "AOUT2L",
+		"Line Out Jack", "AOUT2R",
+		"Line Out Jack", "AOUT3L",
+		"Line Out Jack", "AOUT3R",
+		"Line Out Jack", "AOUT4L",
+		"Line Out Jack", "AOUT4R",
+		"AIN1L", "Line In Jack",
+		"AIN1R", "Line In Jack",
+		"AIN2L", "Line In Jack",
+		"AIN2R", "Line In Jack";
+};
diff --git a/Documentation/devicetree/bindings/sound/fsl-sai.txt b/Documentation/devicetree/bindings/sound/fsl-sai.txt
index 0f4e238..4956b14 100644
--- a/Documentation/devicetree/bindings/sound/fsl-sai.txt
+++ b/Documentation/devicetree/bindings/sound/fsl-sai.txt
@@ -18,12 +18,26 @@
 - pinctrl-names: Must contain a "default" entry.
 - pinctrl-NNN: One property must exist for each entry in pinctrl-names.
   See ../pinctrl/pinctrl-bindings.txt for details of the property values.
-- big-endian-regs: If this property is absent, the little endian mode will
-  be in use as default, or the big endian mode will be in use for all the
-  device registers.
-- big-endian-data: If this property is absent, the little endian mode will
-  be in use as default, or the big endian mode will be in use for all the
-  fifo data.
+- big-endian: Boolean property, required if all the FTM_PWM registers
+  are big-endian rather than little-endian.
+- lsb-first: Configures whether the LSB or the MSB is transmitted first for
+  the fifo data. If this property is absent, the MSB is transmitted first as
+  default, or the LSB is transmitted first.
+- fsl,sai-synchronous-rx: This is a boolean property. If present, indicating
+  that SAI will work in the synchronous mode (sync Tx with Rx) which means
+  both the transimitter and receiver will send and receive data by following
+  receiver's bit clocks and frame sync clocks.
+- fsl,sai-asynchronous: This is a boolean property. If present, indicating
+  that SAI will work in the asynchronous mode, which means both transimitter
+  and receiver will send and receive data by following their own bit clocks
+  and frame sync clocks separately.
+
+Note:
+- If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the
+  default synchronous mode (sync Rx with Tx) will be used, which means both
+  transimitter and receiver will send and receive data by following clocks
+  of transimitter.
+- fsl,sai-asynchronous and fsl,sai-synchronous-rx are exclusive.
 
 Example:
 sai2: sai@40031000 {
@@ -38,6 +52,6 @@
 	      dma-names = "tx", "rx";
 	      dmas = <&edma0 0 VF610_EDMA_MUXID0_SAI2_TX>,
 		   <&edma0 0 VF610_EDMA_MUXID0_SAI2_RX>;
-	      big-endian-regs;
-	      big-endian-data;
+	      big-endian;
+	      lsb-first;
 };
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-es8328.txt b/Documentation/devicetree/bindings/sound/imx-audio-es8328.txt
new file mode 100644
index 0000000..07b68ab
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/imx-audio-es8328.txt
@@ -0,0 +1,60 @@
+Freescale i.MX audio complex with ES8328 codec
+
+Required properties:
+- compatible       : "fsl,imx-audio-es8328"
+- model            : The user-visible name of this sound complex
+- ssi-controller   : The phandle of the i.MX SSI controller
+- jack-gpio        : Optional GPIO for headphone jack
+- audio-amp-supply : Power regulator for speaker amps
+- audio-codec      : The phandle of the ES8328 audio codec
+- audio-routing    : A list of the connections between audio components.
+                     Each entry is a pair of strings, the first being the
+		     connection's sink, the second being the connection's
+		     source. Valid names could be power supplies, ES8328
+		     pins, and the jacks on the board:
+
+			Power supplies:
+			   * audio-amp
+
+			ES8328 pins:
+			   * LOUT1
+			   * LOUT2
+			   * ROUT1
+			   * ROUT2
+			   * LINPUT1
+			   * LINPUT2
+			   * RINPUT1
+			   * RINPUT2
+			   * Mic PGA
+
+			Board connectors:
+			   * Headphone
+			   * Speaker
+			   * Mic Jack
+- mux-int-port     : The internal port of the i.MX audio muxer (AUDMUX)
+- mux-ext-port     : The external port of the i.MX audio muxer (AUDMIX)
+
+Note: The AUDMUX port numbering should start at 1, which is consistent with
+hardware manual.
+
+Example:
+
+sound {
+	compatible = "fsl,imx-audio-es8328";
+	model = "imx-audio-es8328";
+	ssi-controller = <&ssi1>;
+	audio-codec = <&codec>;
+	jack-gpio = <&gpio5 15 0>;
+	audio-amp-supply = <&reg_audio_amp>;
+	audio-routing =
+		"Speaker", "LOUT2",
+		"Speaker", "ROUT2",
+		"Speaker", "audio-amp",
+		"Headphone", "ROUT1",
+		"Headphone", "LOUT1",
+		"LINPUT1", "Mic Jack",
+		"RINPUT1", "Mic Jack",
+		"Mic Jack", "Mic Bias";
+	mux-int-port = <1>;
+	mux-ext-port = <3>;
+};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt
index 9c7c55c..c949abc 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt
@@ -25,6 +25,7 @@
 
 Optional properties:
 - nvidia,hp-det-gpios : The GPIO that detect headphones are plugged in
+- nvidia,mic-det-gpios : The GPIO that detect microphones are plugged in
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/sound/rt5677.txt b/Documentation/devicetree/bindings/sound/rt5677.txt
new file mode 100644
index 0000000..0701b83
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rt5677.txt
@@ -0,0 +1,59 @@
+RT5677 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : "realtek,rt5677".
+
+- reg : The I2C address of the device.
+
+- interrupts : The CODEC's interrupt output.
+
+- gpio-controller : Indicates this device is a GPIO controller.
+
+- #gpio-cells : Should be two. The first cell is the pin number and the
+  second cell is used to specify optional parameters (currently unused).
+
+Optional properties:
+
+- realtek,pow-ldo2-gpio : The GPIO that controls the CODEC's POW_LDO2 pin.
+
+- realtek,in1-differential
+- realtek,in2-differential
+- realtek,lout1-differential
+- realtek,lout2-differential
+- realtek,lout3-differential
+  Boolean. Indicate MIC1/2 input and LOUT1/2/3 outputs are differential,
+  rather than single-ended.
+
+Pins on the device (for linking into audio routes):
+
+  * IN1P
+  * IN1N
+  * IN2P
+  * IN2N
+  * MICBIAS1
+  * DMIC1
+  * DMIC2
+  * DMIC3
+  * DMIC4
+  * LOUT1
+  * LOUT2
+  * LOUT3
+
+Example:
+
+rt5677 {
+	compatible = "realtek,rt5677";
+	reg = <0x2c>;
+	interrupt-parent = <&gpio>;
+	interrupts = <TEGRA_GPIO(W, 3) GPIO_ACTIVE_HIGH>;
+
+	gpio-controller;
+	#gpio-cells = <2>;
+
+	realtek,pow-ldo2-gpio =
+		<&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
+	realtek,in1-differential = "true";
+};
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt
index c2e9841..c3cba600 100644
--- a/Documentation/devicetree/bindings/sound/simple-card.txt
+++ b/Documentation/devicetree/bindings/sound/simple-card.txt
@@ -17,6 +17,10 @@
 					  source.
 - simple-audio-card,mclk-fs             : Multiplication factor between stream rate and codec
   					  mclk.
+- simple-audio-card,hp-det-gpio		: Reference to GPIO that signals when
+					  headphones are attached.
+- simple-audio-card,mic-det-gpio	: Reference to GPIO that signals when
+					  a microphone is attached.
 
 Optional subnodes:
 
diff --git a/Documentation/devicetree/bindings/sound/ssm4567.txt b/Documentation/devicetree/bindings/sound/ssm4567.txt
new file mode 100644
index 0000000..ec3d9e7
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ssm4567.txt
@@ -0,0 +1,15 @@
+Analog Devices SSM4567 audio amplifier
+
+This device supports I2C only.
+
+Required properties:
+  - compatible : Must be "adi,ssm4567"
+  - reg : the I2C address of the device. This will either be 0x34 (LR_SEL/ADDR connected to AGND),
+	0x35 (LR_SEL/ADDR connected to IOVDD) or 0x36 (LR_SEL/ADDR open).
+
+Example:
+
+	ssm4567: ssm4567@34 {
+		compatible = "adi,ssm4567";
+		reg = <0x34>;
+	};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index ac7269f..34cc1bf 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -48,6 +48,7 @@
 epson	Seiko Epson Corp.
 est	ESTeem Wireless Modems
 eukrea  Eukréa Electromatique
+everest	Everest Semiconductor Co. Ltd.
 excito	Excito
 fsl	Freescale Semiconductor
 GEFanuc	GE Fanuc Intelligent Platforms Embedded Systems, Inc.
diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c
index ca193d1..053150a 100644
--- a/drivers/base/regmap/regmap-i2c.c
+++ b/drivers/base/regmap/regmap-i2c.c
@@ -168,6 +168,8 @@
 	.write = regmap_i2c_write,
 	.gather_write = regmap_i2c_gather_write,
 	.read = regmap_i2c_read,
+	.reg_format_endian_default = REGMAP_ENDIAN_BIG,
+	.val_format_endian_default = REGMAP_ENDIAN_BIG,
 };
 
 static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,
diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c
index 0eb3097..53d1148 100644
--- a/drivers/base/regmap/regmap-spi.c
+++ b/drivers/base/regmap/regmap-spi.c
@@ -109,6 +109,8 @@
 	.async_alloc = regmap_spi_async_alloc,
 	.read = regmap_spi_read,
 	.read_flag_mask = 0x80,
+	.reg_format_endian_default = REGMAP_ENDIAN_BIG,
+	.val_format_endian_default = REGMAP_ENDIAN_BIG,
 };
 
 /**
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 1cf427b..f2281af 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -15,6 +15,7 @@
 #include <linux/export.h>
 #include <linux/mutex.h>
 #include <linux/err.h>
+#include <linux/of.h>
 #include <linux/rbtree.h>
 #include <linux/sched.h>
 
@@ -448,6 +449,66 @@
 }
 EXPORT_SYMBOL_GPL(regmap_attach_dev);
 
+static enum regmap_endian regmap_get_reg_endian(const struct regmap_bus *bus,
+					const struct regmap_config *config)
+{
+	enum regmap_endian endian;
+
+	/* Retrieve the endianness specification from the regmap config */
+	endian = config->reg_format_endian;
+
+	/* If the regmap config specified a non-default value, use that */
+	if (endian != REGMAP_ENDIAN_DEFAULT)
+		return endian;
+
+	/* Retrieve the endianness specification from the bus config */
+	if (bus && bus->reg_format_endian_default)
+		endian = bus->reg_format_endian_default;
+
+	/* If the bus specified a non-default value, use that */
+	if (endian != REGMAP_ENDIAN_DEFAULT)
+		return endian;
+
+	/* Use this if no other value was found */
+	return REGMAP_ENDIAN_BIG;
+}
+
+static enum regmap_endian regmap_get_val_endian(struct device *dev,
+					const struct regmap_bus *bus,
+					const struct regmap_config *config)
+{
+	struct device_node *np = dev->of_node;
+	enum regmap_endian endian;
+
+	/* Retrieve the endianness specification from the regmap config */
+	endian = config->val_format_endian;
+
+	/* If the regmap config specified a non-default value, use that */
+	if (endian != REGMAP_ENDIAN_DEFAULT)
+		return endian;
+
+	/* Parse the device's DT node for an endianness specification */
+	if (of_property_read_bool(np, "big-endian"))
+		endian = REGMAP_ENDIAN_BIG;
+	else if (of_property_read_bool(np, "little-endian"))
+		endian = REGMAP_ENDIAN_LITTLE;
+
+	/* If the endianness was specified in DT, use that */
+	if (endian != REGMAP_ENDIAN_DEFAULT)
+		return endian;
+
+	/* Retrieve the endianness specification from the bus config */
+	if (bus && bus->val_format_endian_default)
+		endian = bus->val_format_endian_default;
+
+	/* If the bus specified a non-default value, use that */
+	if (endian != REGMAP_ENDIAN_DEFAULT)
+		return endian;
+
+	/* Use this if no other value was found */
+	return REGMAP_ENDIAN_BIG;
+}
+
 /**
  * regmap_init(): Initialise register map
  *
@@ -551,17 +612,8 @@
 		map->reg_read  = _regmap_bus_read;
 	}
 
-	reg_endian = config->reg_format_endian;
-	if (reg_endian == REGMAP_ENDIAN_DEFAULT)
-		reg_endian = bus->reg_format_endian_default;
-	if (reg_endian == REGMAP_ENDIAN_DEFAULT)
-		reg_endian = REGMAP_ENDIAN_BIG;
-
-	val_endian = config->val_format_endian;
-	if (val_endian == REGMAP_ENDIAN_DEFAULT)
-		val_endian = bus->val_format_endian_default;
-	if (val_endian == REGMAP_ENDIAN_DEFAULT)
-		val_endian = REGMAP_ENDIAN_BIG;
+	reg_endian = regmap_get_reg_endian(bus, config);
+	val_endian = regmap_get_val_endian(dev, bus, config);
 
 	switch (config->reg_bits + map->reg_shift) {
 	case 2:
diff --git a/include/dt-bindings/sound/cs35l32.h b/include/dt-bindings/sound/cs35l32.h
new file mode 100644
index 0000000..0c6d6a3
--- /dev/null
+++ b/include/dt-bindings/sound/cs35l32.h
@@ -0,0 +1,26 @@
+#ifndef __DT_CS35L32_H
+#define __DT_CS35L32_H
+
+#define CS35L32_BOOST_MGR_AUTO		0
+#define CS35L32_BOOST_MGR_AUTO_AUDIO	1
+#define CS35L32_BOOST_MGR_BYPASS	2
+#define CS35L32_BOOST_MGR_FIXED		3
+
+#define CS35L32_DATA_CFG_LR_VP		0
+#define CS35L32_DATA_CFG_LR_STAT	1
+#define CS35L32_DATA_CFG_LR		2
+#define CS35L32_DATA_CFG_LR_VPSTAT	3
+
+#define CS35L32_BATT_THRESH_3_1V	0
+#define CS35L32_BATT_THRESH_3_2V	1
+#define CS35L32_BATT_THRESH_3_3V	2
+#define CS35L32_BATT_THRESH_3_4V	3
+
+#define CS35L32_BATT_RECOV_3_1V		0
+#define CS35L32_BATT_RECOV_3_2V		1
+#define CS35L32_BATT_RECOV_3_3V		2
+#define CS35L32_BATT_RECOV_3_4V		3
+#define CS35L32_BATT_RECOV_3_5V		4
+#define CS35L32_BATT_RECOV_3_6V		5
+
+#endif /* __DT_CS35L32_H */
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 6f3e10c..e862497 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -183,6 +183,7 @@
 #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)
+#define SNDRV_PCM_FMTBIT_DSD_U32_LE	_SNDRV_PCM_FMTBIT(DSD_U32_LE)
 
 #ifdef SNDRV_LITTLE_ENDIAN
 #define SNDRV_PCM_FMTBIT_S16		SNDRV_PCM_FMTBIT_S16_LE
@@ -365,6 +366,7 @@
 
 struct snd_pcm_group {		/* keep linked substreams */
 	spinlock_t lock;
+	struct mutex mutex;
 	struct list_head substreams;
 	int count;
 };
@@ -460,6 +462,7 @@
 	void (*private_free) (struct snd_pcm *pcm);
 	struct device *dev; /* actual hw device this belongs to */
 	bool internal; /* pcm is for internal use only */
+	bool nonatomic; /* whole PCM operations are in non-atomic context */
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
 	struct snd_pcm_oss oss;
 #endif
@@ -492,8 +495,6 @@
  *  Native I/O
  */
 
-extern rwlock_t snd_pcm_link_rwlock;
-
 int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info);
 int snd_pcm_info_user(struct snd_pcm_substream *substream,
 		      struct snd_pcm_info __user *info);
@@ -537,41 +538,18 @@
 	return substream->group != &substream->self_group;
 }
 
-static inline void snd_pcm_stream_lock(struct snd_pcm_substream *substream)
-{
-	read_lock(&snd_pcm_link_rwlock);
-	spin_lock(&substream->self_group.lock);
-}
-
-static inline void snd_pcm_stream_unlock(struct snd_pcm_substream *substream)
-{
-	spin_unlock(&substream->self_group.lock);
-	read_unlock(&snd_pcm_link_rwlock);
-}
-
-static inline void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream)
-{
-	read_lock_irq(&snd_pcm_link_rwlock);
-	spin_lock(&substream->self_group.lock);
-}
-
-static inline void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream)
-{
-	spin_unlock(&substream->self_group.lock);
-	read_unlock_irq(&snd_pcm_link_rwlock);
-}
-
-#define snd_pcm_stream_lock_irqsave(substream, flags) \
-do { \
-	read_lock_irqsave(&snd_pcm_link_rwlock, (flags)); \
-	spin_lock(&substream->self_group.lock); \
-} while (0)
-
-#define snd_pcm_stream_unlock_irqrestore(substream, flags) \
-do { \
-	spin_unlock(&substream->self_group.lock); \
-	read_unlock_irqrestore(&snd_pcm_link_rwlock, (flags)); \
-} while (0)
+void snd_pcm_stream_lock(struct snd_pcm_substream *substream);
+void snd_pcm_stream_unlock(struct snd_pcm_substream *substream);
+void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream);
+void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream);
+unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream);
+#define snd_pcm_stream_lock_irqsave(substream, flags)		 \
+	do {							 \
+		typecheck(unsigned long, flags);		 \
+		flags = _snd_pcm_stream_lock_irqsave(substream); \
+	} while (0)
+void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
+				      unsigned long flags);
 
 #define snd_pcm_group_for_each_entry(s, substream) \
 	list_for_each_entry(s, &substream->group->substreams, link_list)
diff --git a/include/sound/rt5645.h b/include/sound/rt5645.h
index 1de744c..a535271 100644
--- a/include/sound/rt5645.h
+++ b/include/sound/rt5645.h
@@ -20,6 +20,9 @@
 	/* 0 = IN2N; 1 = GPIO5; 2 = GPIO11 */
 	unsigned int dmic2_data_pin;
 	/* 0 = IN2P; 1 = GPIO6; 2 = GPIO10; 3 = GPIO12 */
+
+	unsigned int hp_det_gpio;
+	bool gpio_hp_det_active_high;
 };
 
 #endif
diff --git a/include/sound/rt5677.h b/include/sound/rt5677.h
index 3da1431..082670e 100644
--- a/include/sound/rt5677.h
+++ b/include/sound/rt5677.h
@@ -12,10 +12,21 @@
 #ifndef __LINUX_SND_RT5677_H
 #define __LINUX_SND_RT5677_H
 
+enum rt5677_dmic2_clk {
+	RT5677_DMIC_CLK1 = 0,
+	RT5677_DMIC_CLK2 = 1,
+};
+
+
 struct rt5677_platform_data {
-	/* IN1 IN2 can optionally be differential */
+	/* IN1/IN2/LOUT1/LOUT2/LOUT3 can optionally be differential */
 	bool in1_diff;
 	bool in2_diff;
+	bool lout1_diff;
+	bool lout2_diff;
+	bool lout3_diff;
+	/* DMIC2 clock source selection */
+	enum rt5677_dmic2_clk dmic2_clk_pin;
 };
 
 #endif
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index aac04ff..3a4d7da 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -432,6 +432,7 @@
 int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
 				const char *pin);
 void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card);
+unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol);
 
 /* Mostly internal - should not normally be used */
 void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm);
@@ -587,13 +588,13 @@
 	enum snd_soc_bias_level suspend_bias_level;
 	struct delayed_work delayed_work;
 	unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
-
+	/* Go to BIAS_OFF in suspend if the DAPM context is idle */
+	unsigned int suspend_bias_off:1;
 	void (*seq_notifier)(struct snd_soc_dapm_context *,
 			     enum snd_soc_dapm_type, int);
 
 	struct device *dev; /* from parent - for debug */
 	struct snd_soc_component *component; /* parent component */
-	struct snd_soc_codec *codec; /* parent codec */
 	struct snd_soc_card *card; /* parent card */
 
 	/* used during DAPM updates */
diff --git a/include/sound/soc.h b/include/sound/soc.h
index c83a334..7ba7130 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -690,6 +690,17 @@
 struct snd_soc_component_driver {
 	const char *name;
 
+	/* Default control and setup, added after probe() is run */
+	const struct snd_kcontrol_new *controls;
+	unsigned int num_controls;
+	const struct snd_soc_dapm_widget *dapm_widgets;
+	unsigned int num_dapm_widgets;
+	const struct snd_soc_dapm_route *dapm_routes;
+	unsigned int num_dapm_routes;
+
+	int (*probe)(struct snd_soc_component *);
+	void (*remove)(struct snd_soc_component *);
+
 	/* DT */
 	int (*of_xlate_dai_name)(struct snd_soc_component *component,
 				 struct of_phandle_args *args,
@@ -697,6 +708,10 @@
 	void (*seq_notifier)(struct snd_soc_component *, enum snd_soc_dapm_type,
 		int subseq);
 	int (*stream_event)(struct snd_soc_component *, int event);
+
+	/* probe ordering - for components with runtime dependencies */
+	int probe_order;
+	int remove_order;
 };
 
 struct snd_soc_component {
@@ -710,6 +725,7 @@
 
 	unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */
 	unsigned int registered_as_component:1;
+	unsigned int probed:1;
 
 	struct list_head list;
 
@@ -728,9 +744,35 @@
 
 	struct mutex io_mutex;
 
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *debugfs_root;
+#endif
+
+	/*
+	* DO NOT use any of the fields below in drivers, they are temporary and
+	* are going to be removed again soon. If you use them in driver code the
+	* driver will be marked as BROKEN when these fields are removed.
+	*/
+
 	/* Don't use these, use snd_soc_component_get_dapm() */
 	struct snd_soc_dapm_context dapm;
 	struct snd_soc_dapm_context *dapm_ptr;
+
+	const struct snd_kcontrol_new *controls;
+	unsigned int num_controls;
+	const struct snd_soc_dapm_widget *dapm_widgets;
+	unsigned int num_dapm_widgets;
+	const struct snd_soc_dapm_route *dapm_routes;
+	unsigned int num_dapm_routes;
+	struct snd_soc_codec *codec;
+
+	int (*probe)(struct snd_soc_component *);
+	void (*remove)(struct snd_soc_component *);
+
+#ifdef CONFIG_DEBUG_FS
+	void (*init_debugfs)(struct snd_soc_component *component);
+	const char *debugfs_prefix;
+#endif
 };
 
 /* SoC Audio Codec device */
@@ -746,11 +788,9 @@
 	struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
 	unsigned int cache_bypass:1; /* Suppress access to the cache */
 	unsigned int suspended:1; /* Codec is in suspend PM state */
-	unsigned int probed:1; /* Codec has been probed */
 	unsigned int ac97_registered:1; /* Codec has been AC97 registered */
 	unsigned int ac97_created:1; /* Codec has been created by SoC */
 	unsigned int cache_init:1; /* codec cache has been initialized */
-	u32 cache_only;  /* Suppress writes to hardware */
 	u32 cache_sync; /* Cache needs to be synced to hardware */
 
 	/* codec IO */
@@ -766,7 +806,6 @@
 	struct snd_soc_dapm_context dapm;
 
 #ifdef CONFIG_DEBUG_FS
-	struct dentry *debugfs_codec_root;
 	struct dentry *debugfs_reg;
 #endif
 };
@@ -808,15 +847,12 @@
 	int (*set_bias_level)(struct snd_soc_codec *,
 			      enum snd_soc_bias_level level);
 	bool idle_bias_off;
+	bool suspend_bias_off;
 
 	void (*seq_notifier)(struct snd_soc_dapm_context *,
 			     enum snd_soc_dapm_type, int);
 
 	bool ignore_pmdown_time;  /* Doesn't benefit from pmdown delay */
-
-	/* probe ordering - for components with runtime dependencies */
-	int probe_order;
-	int remove_order;
 };
 
 /* SoC platform interface */
@@ -832,14 +868,6 @@
 	int (*pcm_new)(struct snd_soc_pcm_runtime *);
 	void (*pcm_free)(struct snd_pcm *);
 
-	/* Default control and setup, added after probe() is run */
-	const struct snd_kcontrol_new *controls;
-	int num_controls;
-	const struct snd_soc_dapm_widget *dapm_widgets;
-	int num_dapm_widgets;
-	const struct snd_soc_dapm_route *dapm_routes;
-	int num_dapm_routes;
-
 	/*
 	 * For platform caused delay reporting.
 	 * Optional.
@@ -853,13 +881,6 @@
 	/* platform stream compress ops */
 	const struct snd_compr_ops *compr_ops;
 
-	/* probe ordering - for components with runtime dependencies */
-	int probe_order;
-	int remove_order;
-
-	/* platform IO - used for platform DAPM */
-	unsigned int (*read)(struct snd_soc_platform *, unsigned int);
-	int (*write)(struct snd_soc_platform *, unsigned int, unsigned int);
 	int (*bespoke_trigger)(struct snd_pcm_substream *, int);
 };
 
@@ -874,15 +895,10 @@
 	const struct snd_soc_platform_driver *driver;
 
 	unsigned int suspended:1; /* platform is suspended */
-	unsigned int probed:1;
 
 	struct list_head list;
 
 	struct snd_soc_component component;
-
-#ifdef CONFIG_DEBUG_FS
-	struct dentry *debugfs_platform_root;
-#endif
 };
 
 struct snd_soc_dai_link {
@@ -897,7 +913,7 @@
 	 * only for codec to codec links, or systems using device tree.
 	 */
 	const char *cpu_name;
-	const struct device_node *cpu_of_node;
+	struct device_node *cpu_of_node;
 	/*
 	 * You MAY specify the DAI name of the CPU DAI. If this information is
 	 * omitted, the CPU-side DAI is matched using .cpu_name/.cpu_of_node
@@ -909,7 +925,7 @@
 	 * DT/OF node, but not both.
 	 */
 	const char *codec_name;
-	const struct device_node *codec_of_node;
+	struct device_node *codec_of_node;
 	/* You MUST specify the DAI name within the codec */
 	const char *codec_dai_name;
 
@@ -922,7 +938,7 @@
 	 * do not need a platform.
 	 */
 	const char *platform_name;
-	const struct device_node *platform_of_node;
+	struct device_node *platform_of_node;
 	int be_id;	/* optional ID for machine driver BE identification */
 
 	const struct snd_soc_pcm_stream *params;
@@ -994,7 +1010,7 @@
 	const struct device_node *codec_of_node;
 
 	/* codec/machine specific init - e.g. add machine controls */
-	int (*init)(struct snd_soc_dapm_context *dapm);
+	int (*init)(struct snd_soc_component *component);
 };
 
 /* SoC card */
@@ -1112,6 +1128,7 @@
 	struct snd_soc_platform *platform;
 	struct snd_soc_dai *codec_dai;
 	struct snd_soc_dai *cpu_dai;
+	struct snd_soc_component *component; /* Only valid for AUX dev rtds */
 
 	struct snd_soc_dai **codec_dais;
 	unsigned int num_codecs;
@@ -1260,9 +1277,6 @@
 int snd_soc_component_test_bits(struct snd_soc_component *component,
 	unsigned int reg, unsigned int mask, unsigned int value);
 
-int snd_soc_component_init_io(struct snd_soc_component *component,
-	struct regmap *regmap);
-
 /* device driver data */
 
 static inline void snd_soc_card_set_drvdata(struct snd_soc_card *card,
@@ -1276,26 +1290,37 @@
 	return card->drvdata;
 }
 
+static inline void snd_soc_component_set_drvdata(struct snd_soc_component *c,
+		void *data)
+{
+	dev_set_drvdata(c->dev, data);
+}
+
+static inline void *snd_soc_component_get_drvdata(struct snd_soc_component *c)
+{
+	return dev_get_drvdata(c->dev);
+}
+
 static inline void snd_soc_codec_set_drvdata(struct snd_soc_codec *codec,
 		void *data)
 {
-	dev_set_drvdata(codec->dev, data);
+	snd_soc_component_set_drvdata(&codec->component, data);
 }
 
 static inline void *snd_soc_codec_get_drvdata(struct snd_soc_codec *codec)
 {
-	return dev_get_drvdata(codec->dev);
+	return snd_soc_component_get_drvdata(&codec->component);
 }
 
 static inline void snd_soc_platform_set_drvdata(struct snd_soc_platform *platform,
 		void *data)
 {
-	dev_set_drvdata(platform->dev, data);
+	snd_soc_component_set_drvdata(&platform->component, data);
 }
 
 static inline void *snd_soc_platform_get_drvdata(struct snd_soc_platform *platform)
 {
-	return dev_get_drvdata(platform->dev);
+	return snd_soc_component_get_drvdata(&platform->component);
 }
 
 static inline void snd_soc_pcm_set_drvdata(struct snd_soc_pcm_runtime *rtd,
diff --git a/include/sound/vx_core.h b/include/sound/vx_core.h
index f634f8f..cae9c9d 100644
--- a/include/sound/vx_core.h
+++ b/include/sound/vx_core.h
@@ -80,8 +80,6 @@
 
 	unsigned int references;     /* an output pipe may be used for monitoring and/or playback */
 	struct vx_pipe *monitoring_pipe;  /* pointer to the monitoring pipe (capture pipe only)*/
-
-	struct tasklet_struct start_tq;
 };
 
 struct vx_core;
@@ -165,9 +163,7 @@
 	struct snd_vx_hardware *hw;
 	struct snd_vx_ops *ops;
 
-	spinlock_t lock;
-	spinlock_t irq_lock;
-	struct tasklet_struct tq;
+	struct mutex lock;
 
 	unsigned int chip_status;
 	unsigned int pcm_running;
@@ -223,6 +219,7 @@
  * interrupt handler; exported for pcmcia
  */
 irqreturn_t snd_vx_irq_handler(int irq, void *dev);
+irqreturn_t snd_vx_threaded_irq_handler(int irq, void *dev);
 
 /*
  * lowlevel functions
diff --git a/include/trace/events/asoc.h b/include/trace/events/asoc.h
index 0194a64..b04ee7e 100644
--- a/include/trace/events/asoc.h
+++ b/include/trace/events/asoc.h
@@ -175,7 +175,7 @@
 		__entry->path_sink = (long)path->sink;
 	),
 
-	TP_printk("%c%s -> %s -> %s\n",
+	TP_printk("%c%s -> %s -> %s",
 		(int) __entry->path_sink &&
 		(int) __entry->path_connect ? '*' : ' ',
 		__get_str(wname), __get_str(pname), __get_str(psname))
@@ -204,7 +204,7 @@
 		__entry->path_source = (long)path->source;
 	),
 
-	TP_printk("%c%s <- %s <- %s\n",
+	TP_printk("%c%s <- %s <- %s",
 		(int) __entry->path_source &&
 		(int) __entry->path_connect ? '*' : ' ',
 		__get_str(wname), __get_str(pname), __get_str(psname))
@@ -226,7 +226,7 @@
 		__entry->stream = stream;
 	),
 
-	TP_printk("%s: found %d paths\n",
+	TP_printk("%s: found %d paths",
 		__entry->stream ? "capture" : "playback", __entry->paths)
 );
 
diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
index 32168f7..6ee5867 100644
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
@@ -219,7 +219,8 @@
 #define	SNDRV_PCM_FORMAT_G723_40_1B	((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */
 #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
+#define	SNDRV_PCM_FORMAT_DSD_U32_LE	((__force snd_pcm_format_t) 50) /* DSD, 4-byte samples DSD (x32), little endian */
+#define	SNDRV_PCM_FORMAT_LAST		SNDRV_PCM_FORMAT_DSD_U32_LE
 
 #ifdef SNDRV_LITTLE_ENDIAN
 #define	SNDRV_PCM_FORMAT_S16		SNDRV_PCM_FORMAT_S16_LE
diff --git a/sound/core/misc.c b/sound/core/misc.c
index 30e027e..f2e8226 100644
--- a/sound/core/misc.c
+++ b/sound/core/misc.c
@@ -145,6 +145,8 @@
 const struct snd_pci_quirk *
 snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list)
 {
+	if (!pci)
+		return NULL;
 	return snd_pci_quirk_lookup_id(pci->subsystem_vendor,
 				       pci->subsystem_device,
 				       list);
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 43932e8..42ded997b 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -215,6 +215,7 @@
 	FORMAT(G723_40_1B),
 	FORMAT(DSD_U8),
 	FORMAT(DSD_U16_LE),
+	FORMAT(DSD_U32_LE),
 };
 
 const char *snd_pcm_format_name(snd_pcm_format_t format)
@@ -698,6 +699,7 @@
 		}
 		substream->group = &substream->self_group;
 		spin_lock_init(&substream->self_group.lock);
+		mutex_init(&substream->self_group.mutex);
 		INIT_LIST_HEAD(&substream->self_group.substreams);
 		list_add_tail(&substream->link_list, &substream->self_group.substreams);
 		atomic_set(&substream->mmap_count, 0);
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 0032278..dfc2854 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -1113,18 +1113,20 @@
 
 EXPORT_SYMBOL(snd_interval_list);
 
-static int snd_interval_step(struct snd_interval *i, unsigned int min, unsigned int step)
+static int snd_interval_step(struct snd_interval *i, unsigned int step)
 {
 	unsigned int n;
 	int changed = 0;
-	n = (i->min - min) % step;
+	n = i->min % step;
 	if (n != 0 || i->openmin) {
 		i->min += step - n;
+		i->openmin = 0;
 		changed = 1;
 	}
-	n = (i->max - min) % step;
+	n = i->max % step;
 	if (n != 0 || i->openmax) {
 		i->max -= n;
+		i->openmax = 0;
 		changed = 1;
 	}
 	if (snd_interval_checkempty(i)) {
@@ -1427,7 +1429,7 @@
 				struct snd_pcm_hw_rule *rule)
 {
 	unsigned long step = (unsigned long) rule->private;
-	return snd_interval_step(hw_param_interval(params, rule->var), 0, step);
+	return snd_interval_step(hw_param_interval(params, rule->var), step);
 }
 
 /**
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c
index 2c6fd80..ae7a0fe 100644
--- a/sound/core/pcm_misc.c
+++ b/sound/core/pcm_misc.c
@@ -148,6 +148,10 @@
 		.width = 16, .phys = 16, .le = 1, .signd = 0,
 		.silence = { 0x69, 0x69 },
 	},
+	[SNDRV_PCM_FORMAT_DSD_U32_LE] = {
+		.width = 32, .phys = 32, .le = 1, .signd = 0,
+		.silence = { 0x69, 0x69, 0x69, 0x69 },
+	},
 	/* FIXME: the following three formats are not defined properly yet */
 	[SNDRV_PCM_FORMAT_MPEG] = {
 		.le = -1, .signd = -1,
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 8cd2f93..815396d 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -74,11 +74,68 @@
  *
  */
 
-DEFINE_RWLOCK(snd_pcm_link_rwlock);
-EXPORT_SYMBOL(snd_pcm_link_rwlock);
-
+static DEFINE_RWLOCK(snd_pcm_link_rwlock);
 static DECLARE_RWSEM(snd_pcm_link_rwsem);
 
+void snd_pcm_stream_lock(struct snd_pcm_substream *substream)
+{
+	if (substream->pcm->nonatomic) {
+		down_read(&snd_pcm_link_rwsem);
+		mutex_lock(&substream->self_group.mutex);
+	} else {
+		read_lock(&snd_pcm_link_rwlock);
+		spin_lock(&substream->self_group.lock);
+	}
+}
+EXPORT_SYMBOL_GPL(snd_pcm_stream_lock);
+
+void snd_pcm_stream_unlock(struct snd_pcm_substream *substream)
+{
+	if (substream->pcm->nonatomic) {
+		mutex_unlock(&substream->self_group.mutex);
+		up_read(&snd_pcm_link_rwsem);
+	} else {
+		spin_unlock(&substream->self_group.lock);
+		read_unlock(&snd_pcm_link_rwlock);
+	}
+}
+EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock);
+
+void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream)
+{
+	if (!substream->pcm->nonatomic)
+		local_irq_disable();
+	snd_pcm_stream_lock(substream);
+}
+EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq);
+
+void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream)
+{
+	snd_pcm_stream_unlock(substream);
+	if (!substream->pcm->nonatomic)
+		local_irq_enable();
+}
+EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irq);
+
+unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream)
+{
+	unsigned long flags = 0;
+	if (!substream->pcm->nonatomic)
+		local_irq_save(flags);
+	snd_pcm_stream_lock(substream);
+	return flags;
+}
+EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave);
+
+void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
+				      unsigned long flags)
+{
+	snd_pcm_stream_unlock(substream);
+	if (!substream->pcm->nonatomic)
+		local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore);
+
 static inline mm_segment_t snd_enter_user(void)
 {
 	mm_segment_t fs = get_fs();
@@ -727,9 +784,14 @@
 	int res = 0;
 
 	snd_pcm_group_for_each_entry(s, substream) {
-		if (do_lock && s != substream)
-			spin_lock_nested(&s->self_group.lock,
-					 SINGLE_DEPTH_NESTING);
+		if (do_lock && s != substream) {
+			if (s->pcm->nonatomic)
+				mutex_lock_nested(&s->self_group.mutex,
+						  SINGLE_DEPTH_NESTING);
+			else
+				spin_lock_nested(&s->self_group.lock,
+						 SINGLE_DEPTH_NESTING);
+		}
 		res = ops->pre_action(s, state);
 		if (res < 0)
 			goto _unlock;
@@ -755,8 +817,12 @@
 	if (do_lock) {
 		/* unlock streams */
 		snd_pcm_group_for_each_entry(s1, substream) {
-			if (s1 != substream)
-				spin_unlock(&s1->self_group.lock);
+			if (s1 != substream) {
+				if (s1->pcm->nonatomic)
+					mutex_unlock(&s1->self_group.mutex);
+				else
+					spin_unlock(&s1->self_group.lock);
+			}
 			if (s1 == s)	/* end */
 				break;
 		}
@@ -784,6 +850,27 @@
 	return res;
 }
 
+/* call in mutex-protected context */
+static int snd_pcm_action_mutex(struct action_ops *ops,
+				struct snd_pcm_substream *substream,
+				int state)
+{
+	int res;
+
+	if (snd_pcm_stream_linked(substream)) {
+		if (!mutex_trylock(&substream->group->mutex)) {
+			mutex_unlock(&substream->self_group.mutex);
+			mutex_lock(&substream->group->mutex);
+			mutex_lock(&substream->self_group.mutex);
+		}
+		res = snd_pcm_action_group(ops, substream, state, 1);
+		mutex_unlock(&substream->group->mutex);
+	} else {
+		res = snd_pcm_action_single(ops, substream, state);
+	}
+	return res;
+}
+
 /*
  *  Note: call with stream lock
  */
@@ -793,6 +880,9 @@
 {
 	int res;
 
+	if (substream->pcm->nonatomic)
+		return snd_pcm_action_mutex(ops, substream, state);
+
 	if (snd_pcm_stream_linked(substream)) {
 		if (!spin_trylock(&substream->group->lock)) {
 			spin_unlock(&substream->self_group.lock);
@@ -807,6 +897,29 @@
 	return res;
 }
 
+static int snd_pcm_action_lock_mutex(struct action_ops *ops,
+				     struct snd_pcm_substream *substream,
+				     int state)
+{
+	int res;
+
+	down_read(&snd_pcm_link_rwsem);
+	if (snd_pcm_stream_linked(substream)) {
+		mutex_lock(&substream->group->mutex);
+		mutex_lock_nested(&substream->self_group.mutex,
+				  SINGLE_DEPTH_NESTING);
+		res = snd_pcm_action_group(ops, substream, state, 1);
+		mutex_unlock(&substream->self_group.mutex);
+		mutex_unlock(&substream->group->mutex);
+	} else {
+		mutex_lock(&substream->self_group.mutex);
+		res = snd_pcm_action_single(ops, substream, state);
+		mutex_unlock(&substream->self_group.mutex);
+	}
+	up_read(&snd_pcm_link_rwsem);
+	return res;
+}
+
 /*
  *  Note: don't use any locks before
  */
@@ -816,6 +929,9 @@
 {
 	int res;
 
+	if (substream->pcm->nonatomic)
+		return snd_pcm_action_lock_mutex(ops, substream, state);
+
 	read_lock_irq(&snd_pcm_link_rwlock);
 	if (snd_pcm_stream_linked(substream)) {
 		spin_lock(&substream->group->lock);
@@ -1634,7 +1750,8 @@
 	down_write(&snd_pcm_link_rwsem);
 	write_lock_irq(&snd_pcm_link_rwlock);
 	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN ||
-	    substream->runtime->status->state != substream1->runtime->status->state) {
+	    substream->runtime->status->state != substream1->runtime->status->state ||
+	    substream->pcm->nonatomic != substream1->pcm->nonatomic) {
 		res = -EBADFD;
 		goto _end;
 	}
@@ -1646,6 +1763,7 @@
 		substream->group = group;
 		group = NULL;
 		spin_lock_init(&substream->group->lock);
+		mutex_init(&substream->group->mutex);
 		INIT_LIST_HEAD(&substream->group->substreams);
 		list_add_tail(&substream->link_list, &substream->group->substreams);
 		substream->group->count = 1;
@@ -3193,7 +3311,7 @@
 
 #ifndef ARCH_HAS_DMA_MMAP_COHERENT
 /* This should be defined / handled globally! */
-#ifdef CONFIG_ARM
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
 #define ARCH_HAS_DMA_MMAP_COHERENT
 #endif
 #endif
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
index 8359689..e8cc169 100644
--- a/sound/drivers/vx/vx_core.c
+++ b/sound/drivers/vx/vx_core.c
@@ -117,7 +117,7 @@
  *
  * returns 0 if successful, or a negative error code.
  * the error code can be VX-specific, retrieved via vx_get_error().
- * NB: call with spinlock held!
+ * NB: call with mutex held!
  */
 static int vx_transfer_end(struct vx_core *chip, int cmd)
 {
@@ -155,7 +155,7 @@
  *
  * returns 0 if successful, or a negative error code.
  * the error code can be VX-specific, retrieved via vx_get_error().
- * NB: call with spinlock held!
+ * NB: call with mutex held!
  */
 static int vx_read_status(struct vx_core *chip, struct vx_rmh *rmh)
 {
@@ -236,7 +236,7 @@
  * returns 0 if successful, or a negative error code.
  * the error code can be VX-specific, retrieved via vx_get_error().
  * 
- * this function doesn't call spinlock at all.
+ * this function doesn't call mutex lock at all.
  */
 int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
 {
@@ -337,7 +337,7 @@
 
 
 /*
- * vx_send_msg - send a DSP message with spinlock
+ * vx_send_msg - send a DSP message with mutex
  * @rmh: the rmh record to send and receive
  *
  * returns 0 if successful, or a negative error code.
@@ -345,12 +345,11 @@
  */
 int vx_send_msg(struct vx_core *chip, struct vx_rmh *rmh)
 {
-	unsigned long flags;
 	int err;
 
-	spin_lock_irqsave(&chip->lock, flags);
+	mutex_lock(&chip->lock);
 	err = vx_send_msg_nolock(chip, rmh);
-	spin_unlock_irqrestore(&chip->lock, flags);
+	mutex_unlock(&chip->lock);
 	return err;
 }
 
@@ -362,7 +361,7 @@
  * returns 0 if successful, or a negative error code.
  * the error code can be VX-specific, retrieved via vx_get_error().
  *
- * this function doesn't call spinlock at all.
+ * this function doesn't call mutex at all.
  *
  * unlike RMH, no command is sent to DSP.
  */
@@ -398,19 +397,18 @@
 
 
 /*
- * vx_send_rih - send an RIH with spinlock
+ * vx_send_rih - send an RIH with mutex
  * @cmd: the command to send
  *
  * see vx_send_rih_nolock().
  */
 int vx_send_rih(struct vx_core *chip, int cmd)
 {
-	unsigned long flags;
 	int err;
 
-	spin_lock_irqsave(&chip->lock, flags);
+	mutex_lock(&chip->lock);
 	err = vx_send_rih_nolock(chip, cmd);
-	spin_unlock_irqrestore(&chip->lock, flags);
+	mutex_unlock(&chip->lock);
 	return err;
 }
 
@@ -482,30 +480,30 @@
 	int err;
 
 	vx_init_rmh(&chip->irq_rmh, CMD_TEST_IT);
-	spin_lock(&chip->lock);
+	mutex_lock(&chip->lock);
 	err = vx_send_msg_nolock(chip, &chip->irq_rmh);
 	if (err < 0)
 		*ret = 0;
 	else
 		*ret = chip->irq_rmh.Stat[0];
-	spin_unlock(&chip->lock);
+	mutex_unlock(&chip->lock);
 	return err;
 }
 
 
 /*
- * vx_interrupt - soft irq handler
+ * snd_vx_threaded_irq_handler - threaded irq handler
  */
-static void vx_interrupt(unsigned long private_data)
+irqreturn_t snd_vx_threaded_irq_handler(int irq, void *dev)
 {
-	struct vx_core *chip = (struct vx_core *) private_data;
+	struct vx_core *chip = dev;
 	unsigned int events;
 		
 	if (chip->chip_status & VX_STAT_IS_STALE)
-		return;
+		return IRQ_HANDLED;
 
 	if (vx_test_irq_src(chip, &events) < 0)
-		return;
+		return IRQ_HANDLED;
     
 #if 0
 	if (events & 0x000800)
@@ -519,7 +517,7 @@
 	 */
 	if (events & FATAL_DSP_ERROR) {
 		snd_printk(KERN_ERR "vx_core: fatal DSP error!!\n");
-		return;
+		return IRQ_HANDLED;
 	}
 
 	/* The start on time code conditions are filled (ie the time code
@@ -534,8 +532,9 @@
 
 	/* update the pcm streams */
 	vx_pcm_update_intr(chip, events);
+	return IRQ_HANDLED;
 }
-
+EXPORT_SYMBOL(snd_vx_threaded_irq_handler);
 
 /**
  * snd_vx_irq_handler - interrupt handler
@@ -548,8 +547,8 @@
 	    (chip->chip_status & VX_STAT_IS_STALE))
 		return IRQ_NONE;
 	if (! vx_test_and_ack(chip))
-		tasklet_schedule(&chip->tq);
-	return IRQ_HANDLED;
+		return IRQ_WAKE_THREAD;
+	return IRQ_NONE;
 }
 
 EXPORT_SYMBOL(snd_vx_irq_handler);
@@ -790,13 +789,11 @@
 		snd_printk(KERN_ERR "vx_core: no memory\n");
 		return NULL;
 	}
-	spin_lock_init(&chip->lock);
-	spin_lock_init(&chip->irq_lock);
+	mutex_init(&chip->lock);
 	chip->irq = -1;
 	chip->hw = hw;
 	chip->type = hw->type;
 	chip->ops = ops;
-	tasklet_init(&chip->tq, vx_interrupt, (unsigned long)chip);
 	mutex_init(&chip->mixer_mutex);
 
 	chip->card = card;
diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c
index c71b8d1..3b6823f 100644
--- a/sound/drivers/vx/vx_mixer.c
+++ b/sound/drivers/vx/vx_mixer.c
@@ -32,17 +32,15 @@
  */
 static void vx_write_codec_reg(struct vx_core *chip, int codec, unsigned int data)
 {
-	unsigned long flags;
-
 	if (snd_BUG_ON(!chip->ops->write_codec))
 		return;
 
 	if (chip->chip_status & VX_STAT_IS_STALE)
 		return;
 
-	spin_lock_irqsave(&chip->lock, flags);
+	mutex_lock(&chip->lock);
 	chip->ops->write_codec(chip, codec, data);
-	spin_unlock_irqrestore(&chip->lock, flags);
+	mutex_unlock(&chip->lock);
 }
 
 /*
@@ -178,14 +176,12 @@
  */
 static void vx_change_audio_source(struct vx_core *chip, int src)
 {
-	unsigned long flags;
-
 	if (chip->chip_status & VX_STAT_IS_STALE)
 		return;
 
-	spin_lock_irqsave(&chip->lock, flags);
+	mutex_lock(&chip->lock);
 	chip->ops->change_audio_source(chip, src);
-	spin_unlock_irqrestore(&chip->lock, flags);
+	mutex_unlock(&chip->lock);
 }
 
 
diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c
index deed5ef..1146727 100644
--- a/sound/drivers/vx/vx_pcm.c
+++ b/sound/drivers/vx/vx_pcm.c
@@ -229,7 +229,7 @@
 
 	vx_init_rmh(&rmh, CMD_PIPE_STATE);
 	vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0);
-	err = vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ 
+	err = vx_send_msg(chip, &rmh);
 	if (! err)
 		*state = (rmh.Stat[0] & (1 << pipe->number)) ? 1 : 0;
 	return err;
@@ -280,7 +280,7 @@
 	vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0);
 	rmh.Cmd[0] |= 1;
 
-	err = vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ 
+	err = vx_send_msg(chip, &rmh);
 	if (! err) {
 		if (rmh.Stat[0])
 			err = 1;
@@ -300,7 +300,7 @@
 	if (pipe->is_capture)
 		rmh.Cmd[0] |= COMMAND_RECORD_MASK;
 	rmh.Cmd[1] = 1 << pipe->number;
-	return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */
+	return vx_send_msg(chip, &rmh);
 }
 
 /*
@@ -311,7 +311,7 @@
 	struct vx_rmh rmh;
 
 	vx_init_rmh(&rmh, CMD_SEND_IRQA);
-	return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ 
+	return vx_send_msg(chip, &rmh);
 }
 
 
@@ -389,7 +389,7 @@
 	struct vx_rmh rmh;
 	vx_init_rmh(&rmh, CMD_STOP_PIPE);
 	vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0);
-	return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ 
+	return vx_send_msg(chip, &rmh);
 }
 
 
@@ -477,7 +477,7 @@
 	vx_init_rmh(&rmh, CMD_START_ONE_STREAM);
 	vx_set_stream_cmd_params(&rmh, pipe->is_capture, pipe->number);
 	vx_set_differed_time(chip, &rmh, pipe);
-	return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ 
+	return vx_send_msg(chip, &rmh);
 }
 
 
@@ -492,7 +492,7 @@
 
 	vx_init_rmh(&rmh, CMD_STOP_STREAM);
 	vx_set_stream_cmd_params(&rmh, pipe->is_capture, pipe->number);
-	return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ 
+	return vx_send_msg(chip, &rmh);
 }
 
 
@@ -520,8 +520,6 @@
 };
 
 
-static void vx_pcm_delayed_start(unsigned long arg);
-
 /*
  * vx_pcm_playback_open - open callback for playback
  */
@@ -553,7 +551,6 @@
 	pipe->references++;
 
 	pipe->substream = subs;
-	tasklet_init(&pipe->start_tq, vx_pcm_delayed_start, (unsigned long)subs);
 	chip->playback_pipes[audio] = pipe;
 
 	runtime->hw = vx_pcm_playback_hw;
@@ -646,12 +643,12 @@
 	/* we don't need irqsave here, because this function
 	 * is called from either trigger callback or irq handler
 	 */
-	spin_lock(&chip->lock); 
+	mutex_lock(&chip->lock);
 	vx_pseudo_dma_write(chip, runtime, pipe, size);
 	err = vx_notify_end_of_buffer(chip, pipe);
 	/* disconnect the host, SIZE_HBUF command always switches to the stream mode */
 	vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT);
-	spin_unlock(&chip->lock);
+	mutex_unlock(&chip->lock);
 	return err;
 }
 
@@ -728,31 +725,6 @@
 }
 
 /*
- * start the stream and pipe.
- * this function is called from tasklet, which is invoked by the trigger
- * START callback.
- */
-static void vx_pcm_delayed_start(unsigned long arg)
-{
-	struct snd_pcm_substream *subs = (struct snd_pcm_substream *)arg;
-	struct vx_core *chip = subs->pcm->private_data;
-	struct vx_pipe *pipe = subs->runtime->private_data;
-	int err;
-
-	/*  printk( KERN_DEBUG "DDDD tasklet delayed start jiffies = %ld\n", jiffies);*/
-
-	if ((err = vx_start_stream(chip, pipe)) < 0) {
-		snd_printk(KERN_ERR "vx: cannot start stream\n");
-		return;
-	}
-	if ((err = vx_toggle_pipe(chip, pipe, 1)) < 0) {
-		snd_printk(KERN_ERR "vx: cannot start pipe\n");
-		return;
-	}
-	/*   printk( KERN_DEBUG "dddd tasklet delayed start jiffies = %ld \n", jiffies);*/
-}
-
-/*
  * vx_pcm_playback_trigger - trigger callback for playback
  */
 static int vx_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
@@ -769,11 +741,17 @@
 	case SNDRV_PCM_TRIGGER_RESUME:
 		if (! pipe->is_capture)
 			vx_pcm_playback_transfer(chip, subs, pipe, 2);
-		/* FIXME:
-		 * we trigger the pipe using tasklet, so that the interrupts are
-		 * issued surely after the trigger is completed.
-		 */ 
-		tasklet_schedule(&pipe->start_tq);
+		err = vx_start_stream(chip, pipe);
+		if (err < 0) {
+			pr_debug("vx: cannot start stream\n");
+			return err;
+		}
+		err = vx_toggle_pipe(chip, pipe, 1);
+		if (err < 0) {
+			pr_debug("vx: cannot start pipe\n");
+			vx_stop_stream(chip, pipe);
+			return err;
+		}
 		chip->pcm_running++;
 		pipe->running = 1;
 		break;
@@ -955,7 +933,6 @@
 	if (err < 0)
 		return err;
 	pipe->substream = subs;
-	tasklet_init(&pipe->start_tq, vx_pcm_delayed_start, (unsigned long)subs);
 	chip->capture_pipes[audio] = pipe;
 
 	/* check if monitoring is needed */
@@ -1082,7 +1059,7 @@
 		count -= 3;
 	}
 	/* disconnect the host, SIZE_HBUF command always switches to the stream mode */
-	vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT);
+	vx_send_rih(chip, IRQ_CONNECT_STREAM_NEXT);
 	/* read the last pending 6 bytes */
 	count = DMA_READ_ALIGN;
 	while (count > 0) {
@@ -1099,7 +1076,7 @@
 
  _error:
 	/* disconnect the host, SIZE_HBUF command always switches to the stream mode */
-	vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT);
+	vx_send_rih(chip, IRQ_CONNECT_STREAM_NEXT);
 	return;
 }
 
@@ -1275,6 +1252,7 @@
 		pcm->private_data = chip;
 		pcm->private_free = snd_vx_pcm_free;
 		pcm->info_flags = 0;
+		pcm->nonatomic = true;
 		strcpy(pcm->name, chip->card->shortname);
 		chip->pcm[i] = pcm;
 	}
diff --git a/sound/drivers/vx/vx_uer.c b/sound/drivers/vx/vx_uer.c
index b0560fec..ef0b40c 100644
--- a/sound/drivers/vx/vx_uer.c
+++ b/sound/drivers/vx/vx_uer.c
@@ -60,9 +60,9 @@
  */
 static int vx_read_one_cbit(struct vx_core *chip, int index)
 {
-	unsigned long flags;
 	int val;
-	spin_lock_irqsave(&chip->lock, flags);
+
+	mutex_lock(&chip->lock);
 	if (chip->type >= VX_TYPE_VXPOCKET) {
 		vx_outb(chip, CSUER, 1); /* read */
 		vx_outb(chip, RUER, index & XX_UER_CBITS_OFFSET_MASK);
@@ -72,7 +72,7 @@
 		vx_outl(chip, RUER, index & XX_UER_CBITS_OFFSET_MASK);
 		val = (vx_inl(chip, RUER) >> 7) & 0x01;
 	}
-	spin_unlock_irqrestore(&chip->lock, flags);
+	mutex_unlock(&chip->lock);
 	return val;
 }
 
@@ -83,9 +83,8 @@
  */
 static void vx_write_one_cbit(struct vx_core *chip, int index, int val)
 {
-	unsigned long flags;
 	val = !!val;	/* 0 or 1 */
-	spin_lock_irqsave(&chip->lock, flags);
+	mutex_lock(&chip->lock);
 	if (vx_is_pcmcia(chip)) {
 		vx_outb(chip, CSUER, 0); /* write */
 		vx_outb(chip, RUER, (val << 7) | (index & XX_UER_CBITS_OFFSET_MASK));
@@ -93,7 +92,7 @@
 		vx_outl(chip, CSUER, 0); /* write */
 		vx_outl(chip, RUER, (val << 7) | (index & XX_UER_CBITS_OFFSET_MASK));
 	}
-	spin_unlock_irqrestore(&chip->lock, flags);
+	mutex_unlock(&chip->lock);
 }
 
 /*
@@ -190,14 +189,12 @@
  */
 static void vx_change_clock_source(struct vx_core *chip, int source)
 {
-	unsigned long flags;
-
 	/* we mute DAC to prevent clicks */
 	vx_toggle_dac_mute(chip, 1);
-	spin_lock_irqsave(&chip->lock, flags);
+	mutex_lock(&chip->lock);
 	chip->ops->set_clock_source(chip, source);
 	chip->clock_source = source;
-	spin_unlock_irqrestore(&chip->lock, flags);
+	mutex_unlock(&chip->lock);
 	/* unmute */
 	vx_toggle_dac_mute(chip, 0);
 }
@@ -209,11 +206,11 @@
 void vx_set_internal_clock(struct vx_core *chip, unsigned int freq)
 {
 	int clock;
-	unsigned long flags;
+
 	/* Get real clock value */
 	clock = vx_calc_clock_from_freq(chip, freq);
 	snd_printdd(KERN_DEBUG "set internal clock to 0x%x from freq %d\n", clock, freq);
-	spin_lock_irqsave(&chip->lock, flags);
+	mutex_lock(&chip->lock);
 	if (vx_is_pcmcia(chip)) {
 		vx_outb(chip, HIFREQ, (clock >> 8) & 0x0f);
 		vx_outb(chip, LOFREQ, clock & 0xff);
@@ -221,7 +218,7 @@
 		vx_outl(chip, HIFREQ, (clock >> 8) & 0x0f);
 		vx_outl(chip, LOFREQ, clock & 0xff);
 	}
-	spin_unlock_irqrestore(&chip->lock, flags);
+	mutex_unlock(&chip->lock);
 }
 
 
diff --git a/sound/firewire/bebob/bebob_terratec.c b/sound/firewire/bebob/bebob_terratec.c
index eef8ea7..0e4c0bf 100644
--- a/sound/firewire/bebob/bebob_terratec.c
+++ b/sound/firewire/bebob/bebob_terratec.c
@@ -17,10 +17,10 @@
 	unsigned int enable_ext, enable_word;
 	int err;
 
-	err = avc_audio_get_selector(bebob->unit, 0, 0, &enable_ext);
+	err = avc_audio_get_selector(bebob->unit, 0, 9, &enable_ext);
 	if (err < 0)
 		goto end;
-	err = avc_audio_get_selector(bebob->unit, 0, 0, &enable_word);
+	err = avc_audio_get_selector(bebob->unit, 0, 8, &enable_word);
 	if (err < 0)
 		goto end;
 
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
index afb1b44..e9c3833 100644
--- a/sound/pci/au88x0/au88x0.c
+++ b/sound/pci/au88x0/au88x0.c
@@ -48,11 +48,10 @@
 {
 	int rc;
 	if (!(rc = pci_write_config_byte(vortex, 0x40, 0xff))) {
-			printk(KERN_INFO CARD_NAME
-			       ": vortex latency is 0xff\n");
+			dev_info(&vortex->dev, "vortex latency is 0xff\n");
 	} else {
-		printk(KERN_WARNING CARD_NAME
-				": could not set vortex latency: pci error 0x%x\n", rc);
+		dev_warn(&vortex->dev,
+			 "could not set vortex latency: pci error 0x%x\n", rc);
 	}
 }
 
@@ -70,11 +69,10 @@
 	if (!(rc = pci_read_config_byte(via, 0x42, &value))
 			&& ((value & 0x10)
 				|| !(rc = pci_write_config_byte(via, 0x42, value | 0x10)))) {
-		printk(KERN_INFO CARD_NAME
-				": bridge config is 0x%x\n", value | 0x10);
+		dev_info(&via->dev, "bridge config is 0x%x\n", value | 0x10);
 	} else {
-		printk(KERN_WARNING CARD_NAME
-				": could not set vortex latency: pci error 0x%x\n", rc);
+		dev_warn(&via->dev,
+			 "could not set vortex latency: pci error 0x%x\n", rc);
 	}
 }
 
@@ -97,7 +95,8 @@
 					PCI_DEVICE_ID_AMD_FE_GATE_7007, NULL);
 		}
 		if (via) {
-			printk(KERN_INFO CARD_NAME ": Activating latency workaround...\n");
+			dev_info(&vortex->dev,
+				 "Activating latency workaround...\n");
 			vortex_fix_latency(vortex);
 			vortex_fix_agp_bridge(via);
 		}
@@ -153,7 +152,7 @@
 		return err;
 	if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0 ||
 	    pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) < 0) {
-		printk(KERN_ERR "error to set DMA mask\n");
+		dev_err(card->dev, "error to set DMA mask\n");
 		pci_disable_device(pci);
 		return -ENXIO;
 	}
@@ -182,7 +181,7 @@
 
 	chip->mmio = pci_ioremap_bar(pci, 0);
 	if (!chip->mmio) {
-		printk(KERN_ERR "MMIO area remap failed.\n");
+		dev_err(card->dev, "MMIO area remap failed.\n");
 		err = -ENOMEM;
 		goto ioremap_out;
 	}
@@ -191,14 +190,14 @@
 	 * This must be done before we do request_irq otherwise we can get spurious
 	 * interrupts that we do not handle properly and make a mess of things */
 	if ((err = vortex_core_init(chip)) != 0) {
-		printk(KERN_ERR "hw core init failed\n");
+		dev_err(card->dev, "hw core init failed\n");
 		goto core_out;
 	}
 
 	if ((err = request_irq(pci->irq, vortex_interrupt,
 			       IRQF_SHARED, KBUILD_MODNAME,
 	                       chip)) != 0) {
-		printk(KERN_ERR "cannot grab irq\n");
+		dev_err(card->dev, "cannot grab irq\n");
 		goto irq_out;
 	}
 	chip->irq = pci->irq;
@@ -342,11 +341,11 @@
 	chip->rev = pci->revision;
 #ifdef CHIP_AU8830
 	if ((chip->rev) != 0xfe && (chip->rev) != 0xfa) {
-		printk(KERN_ALERT
-		       "vortex: The revision (%x) of your card has not been seen before.\n",
+		dev_alert(card->dev,
+			  "The revision (%x) of your card has not been seen before.\n",
 		       chip->rev);
-		printk(KERN_ALERT
-		       "vortex: Please email the results of 'lspci -vv' to openvortex-dev@nongnu.org.\n");
+		dev_alert(card->dev,
+			  "Please email the results of 'lspci -vv' to openvortex-dev@nongnu.org.\n");
 		snd_card_free(card);
 		err = -ENODEV;
 		return err;
diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h
index 466a5c8..3a8fefe 100644
--- a/sound/pci/au88x0/au88x0.h
+++ b/sound/pci/au88x0/au88x0.h
@@ -243,7 +243,7 @@
 static int vortex_core_shutdown(vortex_t * card);
 static void vortex_enable_int(vortex_t * card);
 static irqreturn_t vortex_interrupt(int irq, void *dev_id);
-static int vortex_alsafmt_aspfmt(int alsafmt);
+static int vortex_alsafmt_aspfmt(int alsafmt, vortex_t *v);
 
 /* Connection  stuff. */
 static void vortex_connect_default(vortex_t * vortex, int en);
@@ -278,7 +278,7 @@
 static void vortex_Vort3D_enable(vortex_t * v);
 static void vortex_Vort3D_disable(vortex_t * v);
 static void vortex_Vort3D_connect(vortex_t * vortex, int en);
-static void vortex_Vort3D_InitializeSource(a3dsrc_t * a, int en);
+static void vortex_Vort3D_InitializeSource(a3dsrc_t *a, int en, vortex_t *v);
 #endif
 
 /* Driver stuff. */
diff --git a/sound/pci/au88x0/au88x0_a3d.c b/sound/pci/au88x0/au88x0_a3d.c
index aad831a..ab0f8731 100644
--- a/sound/pci/au88x0/au88x0_a3d.c
+++ b/sound/pci/au88x0/au88x0_a3d.c
@@ -463,7 +463,7 @@
 static void a3dsrc_ZeroState(a3dsrc_t * a)
 {
 	/*
-	printk(KERN_DEBUG "vortex: ZeroState slice: %d, source %d\n",
+	pr_debug( "vortex: ZeroState slice: %d, source %d\n",
 	       a->slice, a->source);
 	*/
 	a3dsrc_SetAtmosState(a, 0, 0, 0, 0);
@@ -484,12 +484,13 @@
 }
 
 /* Reset entire A3D engine */
-static void a3dsrc_ZeroStateA3D(a3dsrc_t * a)
+static void a3dsrc_ZeroStateA3D(a3dsrc_t *a, vortex_t *v)
 {
 	int i, var, var2;
 
 	if ((a->vortex) == NULL) {
-		printk(KERN_ERR "vortex: ZeroStateA3D: ERROR: a->vortex is NULL\n");
+		dev_err(v->card->dev,
+			"ZeroStateA3D: ERROR: a->vortex is NULL\n");
 		return;
 	}
 
@@ -601,7 +602,7 @@
 	Vort3DRend_Initialize(v, XT_HEADPHONE);
 	for (i = 0; i < NR_A3D; i++) {
 		vortex_A3dSourceHw_Initialize(v, i % 4, i >> 2);
-		a3dsrc_ZeroStateA3D(&(v->a3d[0]));
+		a3dsrc_ZeroStateA3D(&v->a3d[0], v);
 	}
 	/* Register ALSA controls */
 	vortex_a3d_register_controls(v);
@@ -628,15 +629,15 @@
 	v->mixxtlk[0] =
 	    vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN);
 	if (v->mixxtlk[0] < 0) {
-		printk
-		    ("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n");
+		dev_warn(v->card->dev,
+			 "vortex_Vort3D: ERROR: not enough free mixer resources.\n");
 		return;
 	}
 	v->mixxtlk[1] =
 	    vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN);
 	if (v->mixxtlk[1] < 0) {
-		printk
-		    ("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n");
+		dev_warn(v->card->dev,
+			 "vortex_Vort3D: ERROR: not enough free mixer resources.\n");
 		return;
 	}
 #endif
@@ -676,11 +677,11 @@
 }
 
 /* Initialize one single A3D source. */
-static void vortex_Vort3D_InitializeSource(a3dsrc_t * a, int en)
+static void vortex_Vort3D_InitializeSource(a3dsrc_t *a, int en, vortex_t *v)
 {
 	if (a->vortex == NULL) {
-		printk
-		    ("vortex: Vort3D_InitializeSource: A3D source not initialized\n");
+		dev_warn(v->card->dev,
+			 "Vort3D_InitializeSource: A3D source not initialized\n");
 		return;
 	}
 	if (en) {
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
index ae59dba..4667c32 100644
--- a/sound/pci/au88x0/au88x0_core.c
+++ b/sound/pci/au88x0/au88x0_core.c
@@ -285,8 +285,8 @@
 		temp = hwread(vortex->mmio, prev);
 		//printk(KERN_INFO "vortex: mixAddWTD: while addr=%x, val=%x\n", prev, temp);
 		if ((++lifeboat) > 0xf) {
-			printk(KERN_ERR
-			       "vortex_mixer_addWTD: lifeboat overflow\n");
+			dev_err(vortex->card->dev,
+				"vortex_mixer_addWTD: lifeboat overflow\n");
 			return 0;
 		}
 	}
@@ -303,7 +303,7 @@
 
 	eax = hwread(vortex->mmio, VORTEX_MIXER_SR);
 	if (((1 << ch) & eax) == 0) {
-		printk(KERN_ERR "mix ALARM %x\n", eax);
+		dev_err(vortex->card->dev, "mix ALARM %x\n", eax);
 		return 0;
 	}
 	ebp = VORTEX_MIXER_CHNBASE + (ch << 2);
@@ -324,8 +324,8 @@
 			//printk(KERN_INFO "vortex: mixdelWTD: 1 addr=%x, val=%x, src=%x\n", ebx, edx, src);
 			while ((edx & 0xf) != mix) {
 				if ((esi) > 0xf) {
-					printk(KERN_ERR
-					       "vortex: mixdelWTD: error lifeboat overflow\n");
+					dev_err(vortex->card->dev,
+						"mixdelWTD: error lifeboat overflow\n");
 					return 0;
 				}
 				esp14 = ebx;
@@ -492,7 +492,7 @@
 		hwwrite(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2), ratio);
 		temp = hwread(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2));
 		if ((++lifeboat) > 0x9) {
-			printk(KERN_ERR "Vortex: Src cvr fail\n");
+			dev_err(vortex->card->dev, "Src cvr fail\n");
 			break;
 		}
 	}
@@ -545,7 +545,7 @@
 		hwwrite(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2), desired_ratio);
 
 		if ((lifeboat++) > 15) {
-			printk(KERN_ERR "Vortex: could not set src-%d from %d to %d\n",
+			pr_err( "Vortex: could not set src-%d from %d to %d\n",
 			       src, hw_ratio, desired_ratio);
 			break;
 		}
@@ -684,8 +684,8 @@
 		temp = hwread(vortex->mmio, prev);
 		//printk(KERN_INFO "vortex: srcAddWTD: while addr=%x, val=%x\n", prev, temp);
 		if ((++lifeboat) > 0xf) {
-			printk(KERN_ERR
-			       "vortex_src_addWTD: lifeboat overflow\n");
+			dev_err(vortex->card->dev,
+				"vortex_src_addWTD: lifeboat overflow\n");
 			return 0;
 		}
 	}
@@ -703,7 +703,7 @@
 
 	eax = hwread(vortex->mmio, VORTEX_SRCBLOCK_SR);
 	if (((1 << ch) & eax) == 0) {
-		printk(KERN_ERR "src alarm\n");
+		dev_err(vortex->card->dev, "src alarm\n");
 		return 0;
 	}
 	ebp = VORTEX_SRC_CHNBASE + (ch << 2);
@@ -724,8 +724,8 @@
 			//printk(KERN_INFO "vortex: srcdelWTD: 1 addr=%x, val=%x, src=%x\n", ebx, edx, src);
 			while ((edx & 0xf) != src) {
 				if ((esi) > 0xf) {
-					printk
-					    ("vortex: srcdelWTD: error, lifeboat overflow\n");
+					dev_warn(vortex->card->dev,
+						 "srcdelWTD: error, lifeboat overflow\n");
 					return 0;
 				}
 				esp14 = ebx;
@@ -819,8 +819,8 @@
 	do {
 		temp = hwread(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2));
 		if (lifeboat++ > 0xbb8) {
-			printk(KERN_ERR
-			       "Vortex: vortex_fifo_setadbctrl fail\n");
+			dev_err(vortex->card->dev,
+				"vortex_fifo_setadbctrl fail\n");
 			break;
 		}
 	}
@@ -915,7 +915,8 @@
 	do {
 		temp = hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2));
 		if (lifeboat++ > 0xbb8) {
-			printk(KERN_ERR "Vortex: vortex_fifo_setwtctrl fail\n");
+			dev_err(vortex->card->dev,
+				"vortex_fifo_setwtctrl fail\n");
 			break;
 		}
 	}
@@ -970,7 +971,7 @@
     do {
 		temp = hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2));
 		if (lifeboat++ > 0xbb8) {
-			printk(KERN_ERR "Vortex: vortex_fifo_setwtctrl fail (hanging)\n");
+			pr_err( "Vortex: vortex_fifo_setwtctrl fail (hanging)\n");
 			break;
 		}
     } while ((temp & FIFO_RDONLY)&&(temp & FIFO_VALID)&&(temp != 0xFFFFFFFF));
@@ -1042,7 +1043,7 @@
 	for (x = NR_ADB - 1; x >= 0; x--) {
 		hwwrite(vortex->mmio, addr, (FIFO_U0 | FIFO_U1));
 		if (hwread(vortex->mmio, addr) != (FIFO_U0 | FIFO_U1))
-			printk(KERN_ERR "bad adb fifo reset!");
+			dev_err(vortex->card->dev, "bad adb fifo reset!");
 		vortex_fifo_clearadbdata(vortex, x, FIFO_SIZE);
 		addr -= 4;
 	}
@@ -1053,9 +1054,9 @@
 	for (x = NR_WT - 1; x >= 0; x--) {
 		hwwrite(vortex->mmio, addr, FIFO_U0);
 		if (hwread(vortex->mmio, addr) != FIFO_U0)
-			printk(KERN_ERR
-			       "bad wt fifo reset (0x%08x, 0x%08x)!\n",
-			       addr, hwread(vortex->mmio, addr));
+			dev_err(vortex->card->dev,
+				"bad wt fifo reset (0x%08x, 0x%08x)!\n",
+				addr, hwread(vortex->mmio, addr));
 		vortex_fifo_clearwtdata(vortex, x, FIFO_SIZE);
 		addr -= 4;
 	}
@@ -1136,7 +1137,7 @@
 		break;
 	}
 	/*
-	printk(KERN_DEBUG "vortex: cfg0 = 0x%x\nvortex: cfg1=0x%x\n",
+	pr_debug( "vortex: cfg0 = 0x%x\nvortex: cfg1=0x%x\n",
 	       dma->cfg0, dma->cfg1);
 	*/
 	hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFCFG0 + (adbdma << 3), dma->cfg0);
@@ -1213,8 +1214,9 @@
 	if (dma->period_virt >= dma->nr_periods)
 		dma->period_virt -= dma->nr_periods;
 	if (delta != 1)
-		printk(KERN_INFO "vortex: %d virt=%d, real=%d, delta=%d\n",
-		       adbdma, dma->period_virt, dma->period_real, delta);
+		dev_info(vortex->card->dev,
+			 "%d virt=%d, real=%d, delta=%d\n",
+			 adbdma, dma->period_virt, dma->period_real, delta);
 
 	return delta;
 }
@@ -1482,8 +1484,8 @@
 	dma->period_real = page;
 
 	if (delta != 1)
-		printk(KERN_WARNING "vortex: wt virt = %d, delta = %d\n",
-		       dma->period_virt, delta);
+		dev_warn(vortex->card->dev, "wt virt = %d, delta = %d\n",
+			 dma->period_virt, delta);
 
 	return delta;
 }
@@ -1667,9 +1669,9 @@
 		    hwread(vortex->mmio,
 			   VORTEX_ADB_RTBASE + (temp << 2)) & ADB_MASK;
 		if ((lifeboat++) > ADB_MASK) {
-			printk(KERN_ERR
-			       "vortex_adb_addroutes: unending route! 0x%x\n",
-			       *route);
+			dev_err(vortex->card->dev,
+				"vortex_adb_addroutes: unending route! 0x%x\n",
+				*route);
 			return;
 		}
 	}
@@ -1703,9 +1705,9 @@
 		    hwread(vortex->mmio,
 			   VORTEX_ADB_RTBASE + (prev << 2)) & ADB_MASK;
 		if (((lifeboat++) > ADB_MASK) || (temp == ADB_MASK)) {
-			printk(KERN_ERR
-			       "vortex_adb_delroutes: route not found! 0x%x\n",
-			       route0);
+			dev_err(vortex->card->dev,
+				"vortex_adb_delroutes: route not found! 0x%x\n",
+				route0);
 			return;
 		}
 	}
@@ -1967,7 +1969,7 @@
 					  ADB_CODECOUT(0 + 4));
 		vortex_connection_mix_adb(vortex, en, 0x11, mixers[3],
 					  ADB_CODECOUT(1 + 4));
-		/* printk(KERN_DEBUG "SDAC detected "); */
+		/* pr_debug( "SDAC detected "); */
 	}
 #else
 	// Use plain direct output to codec.
@@ -2022,7 +2024,7 @@
 				else
 					vortex->dma_adb[i].resources[restype] |= (1 << i);
 				/*
-				printk(KERN_DEBUG
+				pr_debug(
 				       "vortex: ResManager: type %d out %d\n",
 				       restype, i);
 				*/
@@ -2037,7 +2039,7 @@
 			if (resmap[restype] & (1 << i)) {
 				resmap[restype] &= ~(1 << i);
 				/*
-				printk(KERN_DEBUG
+				pr_debug(
 				       "vortex: ResManager: type %d in %d\n",
 				       restype, i);
 				*/
@@ -2045,7 +2047,9 @@
 			}
 		}
 	}
-	printk(KERN_ERR "vortex: FATAL: ResManager: resource type %d exhausted.\n", restype);
+	dev_err(vortex->card->dev,
+		"FATAL: ResManager: resource type %d exhausted.\n",
+		restype);
 	return -ENOMEM;
 }
 
@@ -2173,11 +2177,13 @@
 				memset(stream->resources, 0,
 				       sizeof(unsigned char) *
 				       VORTEX_RESOURCE_LAST);
-				printk(KERN_ERR "vortex: out of A3D sources. Sorry\n");
+				dev_err(vortex->card->dev,
+					"out of A3D sources. Sorry\n");
 				return -EBUSY;
 			}
 			/* (De)Initialize A3D hardware source. */
-			vortex_Vort3D_InitializeSource(&(vortex->a3d[a3d]), en);
+			vortex_Vort3D_InitializeSource(&vortex->a3d[a3d], en,
+						       vortex);
 		}
 		/* Make SPDIF out exclusive to "spdif" device when in use. */
 		if ((stream->type == VORTEX_PCM_SPDIF) && (en)) {
@@ -2421,7 +2427,7 @@
 	hwread(vortex->mmio, VORTEX_IRQ_SOURCE);
 	// Is at least one IRQ flag set?
 	if (source == 0) {
-		printk(KERN_ERR "vortex: missing irq source\n");
+		dev_err(vortex->card->dev, "missing irq source\n");
 		return IRQ_NONE;
 	}
 
@@ -2429,19 +2435,19 @@
 	// Attend every interrupt source.
 	if (unlikely(source & IRQ_ERR_MASK)) {
 		if (source & IRQ_FATAL) {
-			printk(KERN_ERR "vortex: IRQ fatal error\n");
+			dev_err(vortex->card->dev, "IRQ fatal error\n");
 		}
 		if (source & IRQ_PARITY) {
-			printk(KERN_ERR "vortex: IRQ parity error\n");
+			dev_err(vortex->card->dev, "IRQ parity error\n");
 		}
 		if (source & IRQ_REG) {
-			printk(KERN_ERR "vortex: IRQ reg error\n");
+			dev_err(vortex->card->dev, "IRQ reg error\n");
 		}
 		if (source & IRQ_FIFO) {
-			printk(KERN_ERR "vortex: IRQ fifo error\n");
+			dev_err(vortex->card->dev, "IRQ fifo error\n");
 		}
 		if (source & IRQ_DMA) {
-			printk(KERN_ERR "vortex: IRQ dma error\n");
+			dev_err(vortex->card->dev, "IRQ dma error\n");
 		}
 		handled = 1;
 	}
@@ -2489,7 +2495,7 @@
 	}
 
 	if (!handled) {
-		printk(KERN_ERR "vortex: unknown irq source %x\n", source);
+		dev_err(vortex->card->dev, "unknown irq source %x\n", source);
 	}
 	return IRQ_RETVAL(handled);
 }
@@ -2546,7 +2552,7 @@
 	while (!(hwread(card->mmio, VORTEX_CODEC_CTRL) & 0x100)) {
 		udelay(100);
 		if (lifeboat++ > POLL_COUNT) {
-			printk(KERN_ERR "vortex: ac97 codec stuck busy\n");
+			dev_err(card->card->dev, "ac97 codec stuck busy\n");
 			return;
 		}
 	}
@@ -2572,7 +2578,7 @@
 	while (!(hwread(card->mmio, VORTEX_CODEC_CTRL) & 0x100)) {
 		udelay(100);
 		if (lifeboat++ > POLL_COUNT) {
-			printk(KERN_ERR "vortex: ac97 codec stuck busy\n");
+			dev_err(card->card->dev, "ac97 codec stuck busy\n");
 			return 0xffff;
 		}
 	}
@@ -2586,7 +2592,8 @@
 		udelay(100);
 		data = hwread(card->mmio, VORTEX_CODEC_IO);
 		if (lifeboat++ > POLL_COUNT) {
-			printk(KERN_ERR "vortex: ac97 address never arrived\n");
+			dev_err(card->card->dev,
+				"ac97 address never arrived\n");
 			return 0xffff;
 		}
 	} while ((data & VORTEX_CODEC_ADDMASK) !=
@@ -2683,7 +2690,7 @@
 static int vortex_core_init(vortex_t *vortex)
 {
 
-	printk(KERN_INFO "Vortex: init.... ");
+	dev_info(vortex->card->dev, "init started\n");
 	/* Hardware Init. */
 	hwwrite(vortex->mmio, VORTEX_CTRL, 0xffffffff);
 	msleep(5);
@@ -2728,7 +2735,7 @@
 	//vortex_enable_timer_int(vortex);
 	//vortex_disable_timer_int(vortex);
 
-	printk(KERN_INFO "done.\n");
+	dev_info(vortex->card->dev, "init.... done.\n");
 	spin_lock_init(&vortex->lock);
 
 	return 0;
@@ -2737,7 +2744,7 @@
 static int vortex_core_shutdown(vortex_t * vortex)
 {
 
-	printk(KERN_INFO "Vortex: shutdown...");
+	dev_info(vortex->card->dev, "shutdown started\n");
 #ifndef CHIP_AU8820
 	vortex_eq_free(vortex);
 	vortex_Vort3D_disable(vortex);
@@ -2759,13 +2766,13 @@
 	msleep(5);
 	hwwrite(vortex->mmio, VORTEX_IRQ_SOURCE, 0xffff);
 
-	printk(KERN_INFO "done.\n");
+	dev_info(vortex->card->dev, "shutdown.... done.\n");
 	return 0;
 }
 
 /* Alsa support. */
 
-static int vortex_alsafmt_aspfmt(int alsafmt)
+static int vortex_alsafmt_aspfmt(int alsafmt, vortex_t *v)
 {
 	int fmt;
 
@@ -2793,7 +2800,8 @@
 		break;
 	default:
 		fmt = 0x8;
-		printk(KERN_ERR "vortex: format unsupported %d\n", alsafmt);
+		dev_err(v->card->dev,
+			"format unsupported %d\n", alsafmt);
 		break;
 	}
 	return fmt;
diff --git a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c
index e722053..9585c5c 100644
--- a/sound/pci/au88x0/au88x0_eq.c
+++ b/sound/pci/au88x0/au88x0_eq.c
@@ -845,7 +845,8 @@
 
 	vortex_Eqlzr_GetAllPeaks(vortex, peaks, &count);
 	if (count != 20) {
-		printk(KERN_ERR "vortex: peak count error 20 != %d \n", count);
+		dev_err(vortex->card->dev,
+			"peak count error 20 != %d\n", count);
 		return -1;
 	}
 	for (i = 0; i < 20; i++)
diff --git a/sound/pci/au88x0/au88x0_game.c b/sound/pci/au88x0/au88x0_game.c
index 280f86d..151815b 100644
--- a/sound/pci/au88x0/au88x0_game.c
+++ b/sound/pci/au88x0/au88x0_game.c
@@ -98,7 +98,8 @@
 
 	vortex->gameport = gp = gameport_allocate_port();
 	if (!gp) {
-		printk(KERN_ERR "vortex: cannot allocate memory for gameport\n");
+		dev_err(vortex->card->dev,
+			"cannot allocate memory for gameport\n");
 		return -ENOMEM;
 	}
 
diff --git a/sound/pci/au88x0/au88x0_mpu401.c b/sound/pci/au88x0/au88x0_mpu401.c
index 29e5945..1025e55 100644
--- a/sound/pci/au88x0/au88x0_mpu401.c
+++ b/sound/pci/au88x0/au88x0_mpu401.c
@@ -73,7 +73,7 @@
 	/* Check if anything is OK. */
 	temp = hwread(vortex->mmio, VORTEX_MIDI_DATA);
 	if (temp != MPU401_ACK /*0xfe */ ) {
-		printk(KERN_ERR "midi port doesn't acknowledge!\n");
+		dev_err(vortex->card->dev, "midi port doesn't acknowledge!\n");
 		return -ENODEV;
 	}
 	/* Enable MPU401 interrupts. */
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c
index 9fb03b4..a6d6d8d 100644
--- a/sound/pci/au88x0/au88x0_pcm.c
+++ b/sound/pci/au88x0/au88x0_pcm.c
@@ -227,11 +227,11 @@
 	err =
 	    snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
 	if (err < 0) {
-		printk(KERN_ERR "Vortex: pcm page alloc failed!\n");
+		dev_err(chip->card->dev, "Vortex: pcm page alloc failed!\n");
 		return err;
 	}
 	/*
-	   printk(KERN_INFO "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params),
+	   pr_info( "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params),
 	   params_period_bytes(hw_params), params_channels(hw_params));
 	 */
 	spin_lock_irq(&chip->lock);
@@ -332,7 +332,7 @@
 		dir = 1;
 	else
 		dir = 0;
-	fmt = vortex_alsafmt_aspfmt(runtime->format);
+	fmt = vortex_alsafmt_aspfmt(runtime->format, chip);
 	spin_lock_irq(&chip->lock);
 	if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
 		vortex_adbdma_setmode(chip, dma, 1, dir, fmt,
@@ -371,7 +371,7 @@
 		}
 #ifndef CHIP_AU8810
 		else {
-			printk(KERN_INFO "vortex: wt start %d\n", dma);
+			dev_info(chip->card->dev, "wt start %d\n", dma);
 			vortex_wtdma_startfifo(chip, dma);
 		}
 #endif
@@ -384,7 +384,7 @@
 			vortex_adbdma_stopfifo(chip, dma);
 #ifndef CHIP_AU8810
 		else {
-			printk(KERN_INFO "vortex: wt stop %d\n", dma);
+			dev_info(chip->card->dev, "wt stop %d\n", dma);
 			vortex_wtdma_stopfifo(chip, dma);
 		}
 #endif
diff --git a/sound/pci/au88x0/au88x0_synth.c b/sound/pci/au88x0/au88x0_synth.c
index 922a84b..78e12f4 100644
--- a/sound/pci/au88x0/au88x0_synth.c
+++ b/sound/pci/au88x0/au88x0_synth.c
@@ -90,7 +90,7 @@
 	hwwrite(vortex->mmio, WT_PARM(wt, 2), 0);
 
 	temp = hwread(vortex->mmio, WT_PARM(wt, 3));
-	printk(KERN_DEBUG "vortex: WT PARM3: %x\n", temp);
+	dev_dbg(vortex->card->dev, "WT PARM3: %x\n", temp);
 	//hwwrite(vortex->mmio, WT_PARM(wt, 3), temp);
 
 	hwwrite(vortex->mmio, WT_DELAY(wt, 0), 0);
@@ -98,7 +98,8 @@
 	hwwrite(vortex->mmio, WT_DELAY(wt, 2), 0);
 	hwwrite(vortex->mmio, WT_DELAY(wt, 3), 0);
 
-	printk(KERN_DEBUG "vortex: WT GMODE: %x\n", hwread(vortex->mmio, WT_GMODE(wt)));
+	dev_dbg(vortex->card->dev, "WT GMODE: %x\n",
+		hwread(vortex->mmio, WT_GMODE(wt)));
 
 	hwwrite(vortex->mmio, WT_PARM(wt, 2), 0xffffffff);
 	hwwrite(vortex->mmio, WT_PARM(wt, 3), 0xcff1c810);
@@ -106,7 +107,8 @@
 	voice->parm0 = voice->parm1 = 0xcfb23e2f;
 	hwwrite(vortex->mmio, WT_PARM(wt, 0), voice->parm0);
 	hwwrite(vortex->mmio, WT_PARM(wt, 1), voice->parm1);
-	printk(KERN_DEBUG "vortex: WT GMODE 2 : %x\n", hwread(vortex->mmio, WT_GMODE(wt)));
+	dev_dbg(vortex->card->dev, "WT GMODE 2 : %x\n",
+		hwread(vortex->mmio, WT_GMODE(wt)));
 	return 0;
 }
 
@@ -196,14 +198,15 @@
 
 	if ((reg == 5) || ((reg >= 7) && (reg <= 10)) || (reg == 0xc)) {
 		if (wt >= (NR_WT / NR_WT_PB)) {
-			printk
-			    ("vortex: WT SetReg: bank out of range. reg=0x%x, wt=%d\n",
-			     reg, wt);
+			dev_warn(vortex->card->dev,
+				 "WT SetReg: bank out of range. reg=0x%x, wt=%d\n",
+				 reg, wt);
 			return 0;
 		}
 	} else {
 		if (wt >= NR_WT) {
-			printk(KERN_ERR "vortex: WT SetReg: voice out of range\n");
+			dev_err(vortex->card->dev,
+				"WT SetReg: voice out of range\n");
 			return 0;
 		}
 	}
@@ -214,42 +217,42 @@
 		/* Voice specific parameters */
 	case 0:		/* running */
 		/*
-		printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+		pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
 		       WT_RUN(wt), (int)val);
 		*/
 		hwwrite(vortex->mmio, WT_RUN(wt), val);
 		return 0xc;
 	case 1:		/* param 0 */
 		/*
-		printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+		pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
 		       WT_PARM(wt,0), (int)val);
 		*/
 		hwwrite(vortex->mmio, WT_PARM(wt, 0), val);
 		return 0xc;
 	case 2:		/* param 1 */
 		/*
-		printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+		pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
 		       WT_PARM(wt,1), (int)val);
 		*/
 		hwwrite(vortex->mmio, WT_PARM(wt, 1), val);
 		return 0xc;
 	case 3:		/* param 2 */
 		/*
-		printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+		pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
 		       WT_PARM(wt,2), (int)val);
 		*/
 		hwwrite(vortex->mmio, WT_PARM(wt, 2), val);
 		return 0xc;
 	case 4:		/* param 3 */
 		/*
-		printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+		pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
 		       WT_PARM(wt,3), (int)val);
 		*/
 		hwwrite(vortex->mmio, WT_PARM(wt, 3), val);
 		return 0xc;
 	case 6:		/* mute */
 		/*
-		printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+		pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
 		       WT_MUTE(wt), (int)val);
 		*/
 		hwwrite(vortex->mmio, WT_MUTE(wt), val);
@@ -257,7 +260,7 @@
 	case 0xb:
 			/* delay */
 		/*
-		printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+		pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
 		       WT_DELAY(wt,0), (int)val);
 		*/
 		hwwrite(vortex->mmio, WT_DELAY(wt, 3), val);
@@ -285,7 +288,7 @@
 		return 0;
 	}
 	/*
-	printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", ecx, (int)val);
+	pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n", ecx, (int)val);
 	*/
 	hwwrite(vortex->mmio, ecx, val);
 	return 1;
diff --git a/sound/pci/ctxfi/ctamixer.c b/sound/pci/ctxfi/ctamixer.c
index fee35cf..c7dc38d 100644
--- a/sound/pci/ctxfi/ctamixer.c
+++ b/sound/pci/ctxfi/ctamixer.c
@@ -258,7 +258,8 @@
 	}
 	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
 	if (err) {
-		printk(KERN_ERR "ctxfi: Can't meet AMIXER resource request!\n");
+		dev_err(mgr->card->dev,
+			"Can't meet AMIXER resource request!\n");
 		goto error;
 	}
 
@@ -296,7 +297,7 @@
 	return 0;
 }
 
-int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr)
+int amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr)
 {
 	int err;
 	struct amixer_mgr *amixer_mgr;
@@ -314,6 +315,7 @@
 
 	amixer_mgr->get_amixer = get_amixer_rsc;
 	amixer_mgr->put_amixer = put_amixer_rsc;
+	amixer_mgr->card = hw->card;
 
 	*ramixer_mgr = amixer_mgr;
 
@@ -411,7 +413,8 @@
 	}
 	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
 	if (err) {
-		printk(KERN_ERR "ctxfi: Can't meet SUM resource request!\n");
+		dev_err(mgr->card->dev,
+			"Can't meet SUM resource request!\n");
 		goto error;
 	}
 
@@ -449,7 +452,7 @@
 	return 0;
 }
 
-int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr)
+int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr)
 {
 	int err;
 	struct sum_mgr *sum_mgr;
@@ -467,6 +470,7 @@
 
 	sum_mgr->get_sum = get_sum_rsc;
 	sum_mgr->put_sum = put_sum_rsc;
+	sum_mgr->card = hw->card;
 
 	*rsum_mgr = sum_mgr;
 
diff --git a/sound/pci/ctxfi/ctamixer.h b/sound/pci/ctxfi/ctamixer.h
index cc49e5a..72f42f2 100644
--- a/sound/pci/ctxfi/ctamixer.h
+++ b/sound/pci/ctxfi/ctamixer.h
@@ -21,6 +21,7 @@
 
 #include "ctresource.h"
 #include <linux/spinlock.h>
+#include <sound/core.h>
 
 /* Define the descriptor of a summation node resource */
 struct sum {
@@ -35,6 +36,7 @@
 
 struct sum_mgr {
 	struct rsc_mgr mgr;	/* Basic resource manager info */
+	struct snd_card *card;	/* pointer to this card */
 	spinlock_t mgr_lock;
 
 	 /* request one sum resource */
@@ -45,7 +47,7 @@
 };
 
 /* Constructor and destructor of daio resource manager */
-int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr);
+int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr);
 int sum_mgr_destroy(struct sum_mgr *sum_mgr);
 
 /* Define the descriptor of a amixer resource */
@@ -79,6 +81,7 @@
 
 struct amixer_mgr {
 	struct rsc_mgr mgr;	/* Basic resource manager info */
+	struct snd_card *card;	/* pointer to this card */
 	spinlock_t mgr_lock;
 
 	 /* request one amixer resource */
@@ -90,7 +93,7 @@
 };
 
 /* Constructor and destructor of amixer resource manager */
-int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr);
+int amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr);
 int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr);
 
 #endif /* CTAMIXER_H */
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
index af632bd..4546590 100644
--- a/sound/pci/ctxfi/ctatc.c
+++ b/sound/pci/ctxfi/ctatc.c
@@ -106,11 +106,11 @@
 			    .public_name = "Mixer"}
 };
 
-typedef int (*create_t)(void *, void **);
+typedef int (*create_t)(struct hw *, void **);
 typedef int (*destroy_t)(void *);
 
 static struct {
-	int (*create)(void *hw, void **rmgr);
+	int (*create)(struct hw *hw, void **rmgr);
 	int (*destroy)(void *mgr);
 } rsc_mgr_funcs[NUM_RSCTYP] = {
 	[SRC] 		= { .create 	= (create_t)src_mgr_create,
@@ -171,7 +171,8 @@
 	return atc->vm->get_ptp_phys(atc->vm, index);
 }
 
-static unsigned int convert_format(snd_pcm_format_t snd_format)
+static unsigned int convert_format(snd_pcm_format_t snd_format,
+				   struct snd_card *card)
 {
 	switch (snd_format) {
 	case SNDRV_PCM_FORMAT_U8:
@@ -185,7 +186,7 @@
 	case SNDRV_PCM_FORMAT_FLOAT_LE:
 		return SRC_SF_F32;
 	default:
-		printk(KERN_ERR "ctxfi: not recognized snd format is %d \n",
+		dev_err(card->dev, "not recognized snd format is %d\n",
 			snd_format);
 		return SRC_SF_S16;
 	}
@@ -268,7 +269,8 @@
 	src = apcm->src;
 	src->ops->set_pitch(src, pitch);
 	src->ops->set_rom(src, select_rom(pitch));
-	src->ops->set_sf(src, convert_format(apcm->substream->runtime->format));
+	src->ops->set_sf(src, convert_format(apcm->substream->runtime->format,
+					     atc->card));
 	src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL));
 
 	/* Get AMIXER resource */
@@ -738,7 +740,8 @@
 
 	/*  Set up recording SRC */
 	src = apcm->src;
-	src->ops->set_sf(src, convert_format(apcm->substream->runtime->format));
+	src->ops->set_sf(src, convert_format(apcm->substream->runtime->format,
+					     atc->card));
 	src->ops->set_sa(src, apcm->vm_block->addr);
 	src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size);
 	src->ops->set_ca(src, apcm->vm_block->addr);
@@ -807,7 +810,8 @@
 	src = apcm->src;
 	src->ops->set_pitch(src, pitch);
 	src->ops->set_rom(src, select_rom(pitch));
-	src->ops->set_sf(src, convert_format(apcm->substream->runtime->format));
+	src->ops->set_sf(src, convert_format(apcm->substream->runtime->format,
+					     atc->card));
 	src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL));
 	src->ops->set_bp(src, 1);
 
@@ -1235,7 +1239,7 @@
 	}
 
 	if (atc->hw)
-		destroy_hw_obj((struct hw *)atc->hw);
+		destroy_hw_obj(atc->hw);
 
 	/* Destroy device virtual memory manager object */
 	if (atc->vm) {
@@ -1282,9 +1286,9 @@
 	p = snd_pci_quirk_lookup_id(vendor_id, device_id, list);
 	if (p) {
 		if (p->value < 0) {
-			printk(KERN_ERR "ctxfi: "
-			       "Device %04x:%04x is black-listed\n",
-			       vendor_id, device_id);
+			dev_err(atc->card->dev,
+				"Device %04x:%04x is black-listed\n",
+				vendor_id, device_id);
 			return -ENOENT;
 		}
 		atc->model = p->value;
@@ -1315,8 +1319,8 @@
 		err = alsa_dev_funcs[i].create(atc, i,
 				alsa_dev_funcs[i].public_name);
 		if (err) {
-			printk(KERN_ERR "ctxfi: "
-			       "Creating alsa device %d failed!\n", i);
+			dev_err(atc->card->dev,
+				"Creating alsa device %d failed!\n", i);
 			return err;
 		}
 	}
@@ -1332,9 +1336,10 @@
 
 	err = create_hw_obj(atc->pci, atc->chip_type, atc->model, &hw);
 	if (err) {
-		printk(KERN_ERR "Failed to create hw obj!!!\n");
+		dev_err(atc->card->dev, "Failed to create hw obj!!!\n");
 		return err;
 	}
+	hw->card = atc->card;
 	atc->hw = hw;
 
 	/* Initialize card hardware. */
@@ -1351,8 +1356,8 @@
 
 		err = rsc_mgr_funcs[i].create(atc->hw, &atc->rsc_mgrs[i]);
 		if (err) {
-			printk(KERN_ERR "ctxfi: "
-			       "Failed to create rsc_mgr %d!!!\n", i);
+			dev_err(atc->card->dev,
+				"Failed to create rsc_mgr %d!!!\n", i);
 			return err;
 		}
 	}
@@ -1399,8 +1404,9 @@
 		err = daio_mgr->get_daio(daio_mgr, &da_desc,
 					(struct daio **)&atc->daios[i]);
 		if (err) {
-			printk(KERN_ERR "ctxfi: Failed to get DAIO "
-					"resource %d!!!\n", i);
+			dev_err(atc->card->dev,
+				"Failed to get DAIO resource %d!!!\n",
+				i);
 			return err;
 		}
 		atc->n_daio++;
@@ -1603,8 +1609,8 @@
 	/* Do hardware resume. */
 	err = atc_hw_resume(atc);
 	if (err < 0) {
-		printk(KERN_ERR "ctxfi: pci_enable_device failed, "
-		       "disabling device\n");
+		dev_err(atc->card->dev,
+			"pci_enable_device failed, disabling device\n");
 		snd_card_disconnect(atc->card);
 		return err;
 	}
@@ -1701,7 +1707,7 @@
 	/* Find card model */
 	err = atc_identify_card(atc, ssid);
 	if (err < 0) {
-		printk(KERN_ERR "ctatc: Card not recognised\n");
+		dev_err(card->dev, "ctatc: Card not recognised\n");
 		goto error1;
 	}
 
@@ -1717,7 +1723,7 @@
 
 	err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer);
 	if (err) {
-		printk(KERN_ERR "ctxfi: Failed to create mixer obj!!!\n");
+		dev_err(card->dev, "Failed to create mixer obj!!!\n");
 		goto error1;
 	}
 
@@ -1744,6 +1750,6 @@
 
 error1:
 	ct_atc_destroy(atc);
-	printk(KERN_ERR "ctxfi: Something wrong!!!\n");
+	dev_err(card->dev, "Something wrong!!!\n");
 	return err;
 }
diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h
index 5f11ca2..5641334 100644
--- a/sound/pci/ctxfi/ctatc.h
+++ b/sound/pci/ctxfi/ctatc.h
@@ -131,7 +131,7 @@
 	/* Don't touch! Used for internal object. */
 	void *rsc_mgrs[NUM_RSCTYP]; /* chip resource managers */
 	void *mixer;		/* internal mixer object */
-	void *hw;		/* chip specific hardware access object */
+	struct hw *hw;		/* chip specific hardware access object */
 	void **daios;		/* digital audio io resources */
 	void **pcm;		/* SUMs for collecting all pcm stream */
 	void **srcs;		/* Sample Rate Converters for input signal */
diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c
index 84f86bf..c1c3f88 100644
--- a/sound/pci/ctxfi/ctdaio.c
+++ b/sound/pci/ctxfi/ctdaio.c
@@ -140,19 +140,19 @@
 
 static int dao_spdif_get_spos(struct dao *dao, unsigned int *spos)
 {
-	((struct hw *)dao->hw)->dao_get_spos(dao->ctrl_blk, spos);
+	dao->hw->dao_get_spos(dao->ctrl_blk, spos);
 	return 0;
 }
 
 static int dao_spdif_set_spos(struct dao *dao, unsigned int spos)
 {
-	((struct hw *)dao->hw)->dao_set_spos(dao->ctrl_blk, spos);
+	dao->hw->dao_set_spos(dao->ctrl_blk, spos);
 	return 0;
 }
 
 static int dao_commit_write(struct dao *dao)
 {
-	((struct hw *)dao->hw)->dao_commit_write(dao->hw,
+	dao->hw->dao_commit_write(dao->hw,
 		daio_device_index(dao->daio.type, dao->hw), dao->ctrl_blk);
 	return 0;
 }
@@ -277,16 +277,14 @@
 static int dai_set_srt_srcl(struct dai *dai, struct rsc *src)
 {
 	src->ops->master(src);
-	((struct hw *)dai->hw)->dai_srt_set_srcm(dai->ctrl_blk,
-						src->ops->index(src));
+	dai->hw->dai_srt_set_srcm(dai->ctrl_blk, src->ops->index(src));
 	return 0;
 }
 
 static int dai_set_srt_srcr(struct dai *dai, struct rsc *src)
 {
 	src->ops->master(src);
-	((struct hw *)dai->hw)->dai_srt_set_srco(dai->ctrl_blk,
-						src->ops->index(src));
+	dai->hw->dai_srt_set_srco(dai->ctrl_blk, src->ops->index(src));
 	return 0;
 }
 
@@ -297,25 +295,25 @@
 	for (rsr = 0; msr > 1; msr >>= 1)
 		rsr++;
 
-	((struct hw *)dai->hw)->dai_srt_set_rsr(dai->ctrl_blk, rsr);
+	dai->hw->dai_srt_set_rsr(dai->ctrl_blk, rsr);
 	return 0;
 }
 
 static int dai_set_enb_src(struct dai *dai, unsigned int enb)
 {
-	((struct hw *)dai->hw)->dai_srt_set_ec(dai->ctrl_blk, enb);
+	dai->hw->dai_srt_set_ec(dai->ctrl_blk, enb);
 	return 0;
 }
 
 static int dai_set_enb_srt(struct dai *dai, unsigned int enb)
 {
-	((struct hw *)dai->hw)->dai_srt_set_et(dai->ctrl_blk, enb);
+	dai->hw->dai_srt_set_et(dai->ctrl_blk, enb);
 	return 0;
 }
 
 static int dai_commit_write(struct dai *dai)
 {
-	((struct hw *)dai->hw)->dai_commit_write(dai->hw,
+	dai->hw->dai_commit_write(dai->hw,
 		daio_device_index(dai->daio.type, dai->hw), dai->ctrl_blk);
 	return 0;
 }
@@ -331,12 +329,12 @@
 
 static int daio_rsc_init(struct daio *daio,
 			 const struct daio_desc *desc,
-			 void *hw)
+			 struct hw *hw)
 {
 	int err;
 	unsigned int idx_l, idx_r;
 
-	switch (((struct hw *)hw)->chip_type) {
+	switch (hw->chip_type) {
 	case ATC20K1:
 		idx_l = idx_20k1[desc->type].left;
 		idx_r = idx_20k1[desc->type].right;
@@ -360,7 +358,7 @@
 	if (desc->type <= DAIO_OUT_MAX) {
 		daio->rscl.ops = daio->rscr.ops = &daio_out_rsc_ops;
 	} else {
-		switch (((struct hw *)hw)->chip_type) {
+		switch (hw->chip_type) {
 		case ATC20K1:
 			daio->rscl.ops = daio->rscr.ops = &daio_in_rsc_ops_20k1;
 			break;
@@ -445,7 +443,7 @@
 		kfree(dao->imappers);
 		dao->imappers = NULL;
 	}
-	((struct hw *)dao->hw)->dao_put_ctrl_blk(dao->ctrl_blk);
+	dao->hw->dao_put_ctrl_blk(dao->ctrl_blk);
 	dao->hw = dao->ctrl_blk = NULL;
 	daio_rsc_uninit(&dao->daio);
 
@@ -502,7 +500,7 @@
 
 static int dai_rsc_uninit(struct dai *dai)
 {
-	((struct hw *)dai->hw)->dai_put_ctrl_blk(dai->ctrl_blk);
+	dai->hw->dai_put_ctrl_blk(dai->ctrl_blk);
 	dai->hw = dai->ctrl_blk = NULL;
 	daio_rsc_uninit(&dai->daio);
 	return 0;
@@ -541,7 +539,8 @@
 	err = daio_mgr_get_rsc(&mgr->mgr, desc->type);
 	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
 	if (err) {
-		printk(KERN_ERR "Can't meet DAIO resource request!\n");
+		dev_err(mgr->card->dev,
+			"Can't meet DAIO resource request!\n");
 		return err;
 	}
 
@@ -692,7 +691,7 @@
 	return 0;
 }
 
-int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr)
+int daio_mgr_create(struct hw *hw, struct daio_mgr **rdaio_mgr)
 {
 	int err, i;
 	struct daio_mgr *daio_mgr;
@@ -727,12 +726,13 @@
 	daio_mgr->imap_add = daio_imap_add;
 	daio_mgr->imap_delete = daio_imap_delete;
 	daio_mgr->commit_write = daio_mgr_commit_write;
+	daio_mgr->card = hw->card;
 
 	for (i = 0; i < 8; i++) {
-		((struct hw *)hw)->daio_mgr_dsb_dao(daio_mgr->mgr.ctrl_blk, i);
-		((struct hw *)hw)->daio_mgr_dsb_dai(daio_mgr->mgr.ctrl_blk, i);
+		hw->daio_mgr_dsb_dao(daio_mgr->mgr.ctrl_blk, i);
+		hw->daio_mgr_dsb_dai(daio_mgr->mgr.ctrl_blk, i);
 	}
-	((struct hw *)hw)->daio_mgr_commit_write(hw, daio_mgr->mgr.ctrl_blk);
+	hw->daio_mgr_commit_write(hw, daio_mgr->mgr.ctrl_blk);
 
 	*rdaio_mgr = daio_mgr;
 
diff --git a/sound/pci/ctxfi/ctdaio.h b/sound/pci/ctxfi/ctdaio.h
index 85ccb6e..0ebbf35 100644
--- a/sound/pci/ctxfi/ctdaio.h
+++ b/sound/pci/ctxfi/ctdaio.h
@@ -23,6 +23,7 @@
 #include "ctimap.h"
 #include <linux/spinlock.h>
 #include <linux/list.h>
+#include <sound/core.h>
 
 /* Define the descriptor of a daio resource */
 enum DAIOTYP {
@@ -53,14 +54,14 @@
 	struct dao_rsc_ops *ops;	/* DAO specific operations */
 	struct imapper **imappers;
 	struct daio_mgr *mgr;
-	void *hw;
+	struct hw *hw;
 	void *ctrl_blk;
 };
 
 struct dai {
 	struct daio daio;
 	struct dai_rsc_ops *ops;	/* DAI specific operations */
-	void *hw;
+	struct hw *hw;
 	void *ctrl_blk;
 };
 
@@ -98,6 +99,7 @@
 
 struct daio_mgr {
 	struct rsc_mgr mgr;	/* Basic resource manager info */
+	struct snd_card *card;	/* pointer to this card */
 	spinlock_t mgr_lock;
 	spinlock_t imap_lock;
 	struct list_head imappers;
@@ -117,7 +119,7 @@
 };
 
 /* Constructor and destructor of daio resource manager */
-int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr);
+int daio_mgr_create(struct hw *hw, struct daio_mgr **rdaio_mgr);
 int daio_mgr_destroy(struct daio_mgr *daio_mgr);
 
 #endif /* CTDAIO_H */
diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h
index 5977e9a..54cc9cb 100644
--- a/sound/pci/ctxfi/cthardware.h
+++ b/sound/pci/ctxfi/cthardware.h
@@ -20,6 +20,7 @@
 
 #include <linux/types.h>
 #include <linux/pci.h>
+#include <sound/core.h>
 
 enum CHIPTYP {
 	ATC20K1,
@@ -184,9 +185,10 @@
 	void *irq_callback_data;
 
 	struct pci_dev *pci;	/* the pci kernel structure of this card */
+	struct snd_card *card;	/* pointer to this card */
 	int irq;
 	unsigned long io_base;
-	unsigned long mem_base;
+	void __iomem *mem_base;
 
 	enum CHIPTYP chip_type;
 	enum CTCARDS model;
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
index 6ac40be..b425aa8 100644
--- a/sound/pci/ctxfi/cthw20k1.c
+++ b/sound/pci/ctxfi/cthw20k1.c
@@ -1268,7 +1268,8 @@
 
 	/* Set up device page table */
 	if ((~0UL) == info->vm_pgt_phys) {
-		printk(KERN_ERR "Wrong device page table page address!\n");
+		dev_err(hw->card->dev,
+			"Wrong device page table page address!\n");
 		return -1;
 	}
 
@@ -1327,7 +1328,7 @@
 		mdelay(40);
 	}
 	if (i >= 3) {
-		printk(KERN_ALERT "PLL initialization failed!!!\n");
+		dev_alert(hw->card->dev, "PLL initialization failed!!!\n");
 		return -EBUSY;
 	}
 
@@ -1351,7 +1352,7 @@
 			break;
 	}
 	if (!get_field(gctl, GCTL_AID)) {
-		printk(KERN_ALERT "Card Auto-init failed!!!\n");
+		dev_alert(hw->card->dev, "Card Auto-init failed!!!\n");
 		return -EBUSY;
 	}
 
@@ -1802,7 +1803,7 @@
 	unsigned int is_uaa;
 	unsigned int data[4] = {0};
 	unsigned int io_base;
-	void *mem_base;
+	void __iomem *mem_base;
 	int i;
 	const u32 CTLX = CTLBITS('C', 'T', 'L', 'X');
 	const u32 CTL_ = CTLBITS('C', 'T', 'L', '-');
@@ -1911,9 +1912,9 @@
 	/* Set DMA transfer mask */
 	if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 ||
 	    pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) {
-		printk(KERN_ERR "architecture does not support PCI "
-				"busmaster DMA with mask 0x%llx\n",
-		       CT_XFI_DMA_MASK);
+		dev_err(hw->card->dev,
+			"architecture does not support PCI busmaster DMA with mask 0x%llx\n",
+			CT_XFI_DMA_MASK);
 		err = -ENXIO;
 		goto error1;
 	}
@@ -1942,7 +1943,8 @@
 		err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED,
 				  KBUILD_MODNAME, hw);
 		if (err < 0) {
-			printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
+			dev_err(hw->card->dev,
+				"XFi: Cannot get irq %d\n", pci->irq);
 			goto error2;
 		}
 		hw->irq = pci->irq;
@@ -1985,9 +1987,9 @@
 	hw->irq	= -1;
 
 	if (hw->mem_base)
-		iounmap((void *)hw->mem_base);
+		iounmap(hw->mem_base);
 
-	hw->mem_base = (unsigned long)NULL;
+	hw->mem_base = NULL;
 
 	if (hw->io_base)
 		pci_release_regions(hw->pci);
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
index b143886..253899d 100644
--- a/sound/pci/ctxfi/cthw20k2.c
+++ b/sound/pci/ctxfi/cthw20k2.c
@@ -1187,7 +1187,8 @@
 		hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121);
 		hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
 	} else {
-		printk(KERN_ALERT "ctxfi: ERROR!!! Invalid sampling rate!!!\n");
+		dev_alert(hw->card->dev,
+			  "ERROR!!! Invalid sampling rate!!!\n");
 		return -EINVAL;
 	}
 
@@ -1246,8 +1247,8 @@
 
 	/* Set up device page table */
 	if ((~0UL) == info->vm_pgt_phys) {
-		printk(KERN_ALERT "ctxfi: "
-		       "Wrong device page table page address!!!\n");
+		dev_alert(hw->card->dev,
+			  "Wrong device page table page address!!!\n");
 		return -1;
 	}
 
@@ -1352,7 +1353,8 @@
 		break;
 	}
 	if (i >= 1000) {
-		printk(KERN_ALERT "ctxfi: PLL initialization failed!!!\n");
+		dev_alert(hw->card->dev,
+			  "PLL initialization failed!!!\n");
 		return -EBUSY;
 	}
 
@@ -1376,7 +1378,7 @@
 			break;
 	}
 	if (!get_field(gctl, GCTL_AID)) {
-		printk(KERN_ALERT "ctxfi: Card Auto-init failed!!!\n");
+		dev_alert(hw->card->dev, "Card Auto-init failed!!!\n");
 		return -EBUSY;
 	}
 
@@ -1847,7 +1849,7 @@
 	/* Initialize I2C */
 	err = hw20k2_i2c_init(hw, 0x1A, 1, 1);
 	if (err < 0) {
-		printk(KERN_ALERT "ctxfi: Failure to acquire I2C!!!\n");
+		dev_alert(hw->card->dev, "Failure to acquire I2C!!!\n");
 		goto error;
 	}
 
@@ -1890,8 +1892,9 @@
 		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A),
 						MAKE_WM8775_DATA(0x0A));
 	} else {
-		printk(KERN_ALERT "ctxfi: Invalid master sampling "
-				  "rate (msr %d)!!!\n", info->msr);
+		dev_alert(hw->card->dev,
+			  "Invalid master sampling rate (msr %d)!!!\n",
+			  info->msr);
 		err = -EINVAL;
 		goto error;
 	}
@@ -2034,8 +2037,9 @@
 	/* Set DMA transfer mask */
 	if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 ||
 	    pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) {
-		printk(KERN_ERR "ctxfi: architecture does not support PCI "
-		"busmaster DMA with mask 0x%llx\n", CT_XFI_DMA_MASK);
+		dev_err(hw->card->dev,
+			"architecture does not support PCI busmaster DMA with mask 0x%llx\n",
+			CT_XFI_DMA_MASK);
 		err = -ENXIO;
 		goto error1;
 	}
@@ -2046,8 +2050,8 @@
 			goto error1;
 
 		hw->io_base = pci_resource_start(hw->pci, 2);
-		hw->mem_base = (unsigned long)ioremap(hw->io_base,
-					pci_resource_len(hw->pci, 2));
+		hw->mem_base = ioremap(hw->io_base,
+				       pci_resource_len(hw->pci, 2));
 		if (!hw->mem_base) {
 			err = -ENOENT;
 			goto error2;
@@ -2063,7 +2067,8 @@
 		err = request_irq(pci->irq, ct_20k2_interrupt, IRQF_SHARED,
 				  KBUILD_MODNAME, hw);
 		if (err < 0) {
-			printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
+			dev_err(hw->card->dev,
+				"XFi: Cannot get irq %d\n", pci->irq);
 			goto error2;
 		}
 		hw->irq = pci->irq;
@@ -2107,9 +2112,9 @@
 	hw->irq	= -1;
 
 	if (hw->mem_base)
-		iounmap((void *)hw->mem_base);
+		iounmap(hw->mem_base);
 
-	hw->mem_base = (unsigned long)NULL;
+	hw->mem_base = NULL;
 
 	if (hw->io_base)
 		pci_release_regions(hw->pci);
@@ -2229,12 +2234,12 @@
 
 static u32 hw_read_20kx(struct hw *hw, u32 reg)
 {
-	return readl((void *)(hw->mem_base + reg));
+	return readl(hw->mem_base + reg);
 }
 
 static void hw_write_20kx(struct hw *hw, u32 reg, u32 data)
 {
-	writel(data, (void *)(hw->mem_base + reg));
+	writel(data, hw->mem_base + reg);
 }
 
 static struct hw ct20k2_preset = {
diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c
index 48fe0e3..4f4a2a5 100644
--- a/sound/pci/ctxfi/ctmixer.c
+++ b/sound/pci/ctxfi/ctmixer.c
@@ -854,8 +854,8 @@
 	for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
 		err = sum_mgr->get_sum(sum_mgr, &sum_desc, &sum);
 		if (err) {
-			printk(KERN_ERR "ctxfi:Failed to get sum resources for "
-					  "front output!\n");
+			dev_err(mixer->atc->card->dev,
+				"Failed to get sum resources for front output!\n");
 			break;
 		}
 		mixer->sums[i] = sum;
@@ -869,8 +869,8 @@
 	for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
 		err = amixer_mgr->get_amixer(amixer_mgr, &am_desc, &amixer);
 		if (err) {
-			printk(KERN_ERR "ctxfi:Failed to get amixer resources "
-			       "for mixer obj!\n");
+			dev_err(mixer->atc->card->dev,
+				"Failed to get amixer resources for mixer obj!\n");
 			break;
 		}
 		mixer->amixers[i] = amixer;
diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c
index e8a4feb..d86c474 100644
--- a/sound/pci/ctxfi/ctpcm.c
+++ b/sound/pci/ctxfi/ctpcm.c
@@ -217,7 +217,8 @@
 		err = atc->pcm_playback_prepare(atc, apcm);
 
 	if (err < 0) {
-		printk(KERN_ERR "ctxfi: Preparing pcm playback failed!!!\n");
+		dev_err(atc->card->dev,
+			"Preparing pcm playback failed!!!\n");
 		return err;
 	}
 
@@ -324,7 +325,8 @@
 
 	err = atc->pcm_capture_prepare(atc, apcm);
 	if (err < 0) {
-		printk(KERN_ERR "ctxfi: Preparing pcm capture failed!!!\n");
+		dev_err(atc->card->dev,
+			"Preparing pcm capture failed!!!\n");
 		return err;
 	}
 
@@ -435,7 +437,8 @@
 	err = snd_pcm_new(atc->card, "ctxfi", device,
 			  playback_count, capture_count, &pcm);
 	if (err < 0) {
-		printk(KERN_ERR "ctxfi: snd_pcm_new failed!! Err=%d\n", err);
+		dev_err(atc->card->dev, "snd_pcm_new failed!! Err=%d\n",
+			err);
 		return err;
 	}
 
diff --git a/sound/pci/ctxfi/ctresource.c b/sound/pci/ctxfi/ctresource.c
index 7dfaf67..1a97e40 100644
--- a/sound/pci/ctxfi/ctresource.c
+++ b/sound/pci/ctxfi/ctresource.c
@@ -134,7 +134,8 @@
 	.next_conj	= rsc_next_conj,
 };
 
-int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw)
+int
+rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, struct hw *hw)
 {
 	int err = 0;
 
@@ -151,25 +152,24 @@
 
 	switch (type) {
 	case SRC:
-		err = ((struct hw *)hw)->src_rsc_get_ctrl_blk(&rsc->ctrl_blk);
+		err = hw->src_rsc_get_ctrl_blk(&rsc->ctrl_blk);
 		break;
 	case AMIXER:
-		err = ((struct hw *)hw)->
-				amixer_rsc_get_ctrl_blk(&rsc->ctrl_blk);
+		err = hw->amixer_rsc_get_ctrl_blk(&rsc->ctrl_blk);
 		break;
 	case SRCIMP:
 	case SUM:
 	case DAIO:
 		break;
 	default:
-		printk(KERN_ERR
-		       "ctxfi: Invalid resource type value %d!\n", type);
+		dev_err(((struct hw *)hw)->card->dev,
+			"Invalid resource type value %d!\n", type);
 		return -EINVAL;
 	}
 
 	if (err) {
-		printk(KERN_ERR
-		       "ctxfi: Failed to get resource control block!\n");
+		dev_err(((struct hw *)hw)->card->dev,
+			"Failed to get resource control block!\n");
 		return err;
 	}
 
@@ -181,19 +181,18 @@
 	if ((NULL != rsc->hw) && (NULL != rsc->ctrl_blk)) {
 		switch (rsc->type) {
 		case SRC:
-			((struct hw *)rsc->hw)->
-				src_rsc_put_ctrl_blk(rsc->ctrl_blk);
+			rsc->hw->src_rsc_put_ctrl_blk(rsc->ctrl_blk);
 			break;
 		case AMIXER:
-			((struct hw *)rsc->hw)->
-				amixer_rsc_put_ctrl_blk(rsc->ctrl_blk);
+			rsc->hw->amixer_rsc_put_ctrl_blk(rsc->ctrl_blk);
 			break;
 		case SUM:
 		case DAIO:
 			break;
 		default:
-			printk(KERN_ERR "ctxfi: "
-			       "Invalid resource type value %d!\n", rsc->type);
+			dev_err(((struct hw *)rsc->hw)->card->dev,
+				"Invalid resource type value %d!\n",
+				rsc->type);
 			break;
 		}
 
@@ -208,10 +207,9 @@
 }
 
 int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type,
-		 unsigned int amount, void *hw_obj)
+		 unsigned int amount, struct hw *hw)
 {
 	int err = 0;
-	struct hw *hw = hw_obj;
 
 	mgr->type = NUM_RSCTYP;
 
@@ -235,15 +233,15 @@
 	case SUM:
 		break;
 	default:
-		printk(KERN_ERR
-		       "ctxfi: Invalid resource type value %d!\n", type);
+		dev_err(hw->card->dev,
+			"Invalid resource type value %d!\n", type);
 		err = -EINVAL;
 		goto error;
 	}
 
 	if (err) {
-		printk(KERN_ERR
-		       "ctxfi: Failed to get manager control block!\n");
+		dev_err(hw->card->dev,
+			"Failed to get manager control block!\n");
 		goto error;
 	}
 
@@ -268,26 +266,23 @@
 	if ((NULL != mgr->hw) && (NULL != mgr->ctrl_blk)) {
 		switch (mgr->type) {
 		case SRC:
-			((struct hw *)mgr->hw)->
-				src_mgr_put_ctrl_blk(mgr->ctrl_blk);
+			mgr->hw->src_mgr_put_ctrl_blk(mgr->ctrl_blk);
 			break;
 		case SRCIMP:
-			((struct hw *)mgr->hw)->
-				srcimp_mgr_put_ctrl_blk(mgr->ctrl_blk);
+			mgr->hw->srcimp_mgr_put_ctrl_blk(mgr->ctrl_blk);
 			break;
 		case AMIXER:
-			((struct hw *)mgr->hw)->
-				amixer_mgr_put_ctrl_blk(mgr->ctrl_blk);
+			mgr->hw->amixer_mgr_put_ctrl_blk(mgr->ctrl_blk);
 			break;
 		case DAIO:
-			((struct hw *)mgr->hw)->
-				daio_mgr_put_ctrl_blk(mgr->ctrl_blk);
+			mgr->hw->daio_mgr_put_ctrl_blk(mgr->ctrl_blk);
 			break;
 		case SUM:
 			break;
 		default:
-			printk(KERN_ERR "ctxfi: "
-			       "Invalid resource type value %d!\n", mgr->type);
+			dev_err(((struct hw *)mgr->hw)->card->dev,
+				"Invalid resource type value %d!\n",
+				mgr->type);
 			break;
 		}
 
diff --git a/sound/pci/ctxfi/ctresource.h b/sound/pci/ctxfi/ctresource.h
index 0838c2e..9b746c3 100644
--- a/sound/pci/ctxfi/ctresource.h
+++ b/sound/pci/ctxfi/ctresource.h
@@ -38,7 +38,7 @@
 	u32 conj:12;	/* Current conjugate index */
 	u32 msr:4;	/* The Master Sample Rate a resource working on */
 	void *ctrl_blk;	/* Chip specific control info block for a resource */
-	void *hw;	/* Chip specific object for hardware access means */
+	struct hw *hw;	/* Chip specific object for hardware access means */
 	struct rsc_ops *ops;	/* Generic resource operations */
 };
 
@@ -50,7 +50,8 @@
 	int (*output_slot)(const struct rsc *rsc);
 };
 
-int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw);
+int
+rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, struct hw *hw);
 int rsc_uninit(struct rsc *rsc);
 
 struct rsc_mgr {
@@ -59,12 +60,12 @@
 	unsigned int avail; /* The amount of currently available resources */
 	unsigned char *rscs; /* The bit-map for resource allocation */
 	void *ctrl_blk; /* Chip specific control info block */
-	void *hw; /* Chip specific object for hardware access */
+	struct hw *hw; /* Chip specific object for hardware access */
 };
 
 /* Resource management is based on bit-map mechanism */
 int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type,
-		 unsigned int amount, void *hw);
+		 unsigned int amount, struct hw *hw);
 int rsc_mgr_uninit(struct rsc_mgr *mgr);
 int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx);
 int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx);
diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c
index 6e77e863..ec1f084 100644
--- a/sound/pci/ctxfi/ctsrc.c
+++ b/sound/pci/ctxfi/ctsrc.c
@@ -431,7 +431,8 @@
 
 	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
 	if (err) {
-		printk(KERN_ERR "ctxfi: Can't meet SRC resource request!\n");
+		dev_err(mgr->card->dev,
+			"Can't meet SRC resource request!\n");
 		return err;
 	}
 
@@ -543,7 +544,7 @@
 	return 0;
 }
 
-int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr)
+int src_mgr_create(struct hw *hw, struct src_mgr **rsrc_mgr)
 {
 	int err, i;
 	struct src_mgr *src_mgr;
@@ -558,7 +559,7 @@
 		goto error1;
 
 	spin_lock_init(&src_mgr->mgr_lock);
-	conj_mask = ((struct hw *)hw)->src_dirty_conj_mask();
+	conj_mask = hw->src_dirty_conj_mask();
 
 	src_mgr->get_src = get_src_rsc;
 	src_mgr->put_src = put_src_rsc;
@@ -566,12 +567,13 @@
 	src_mgr->src_enable = src_enable;
 	src_mgr->src_disable = src_disable;
 	src_mgr->commit_write = src_mgr_commit_write;
+	src_mgr->card = hw->card;
 
 	/* Disable all SRC resources. */
 	for (i = 0; i < 256; i++)
-		((struct hw *)hw)->src_mgr_dsb_src(src_mgr->mgr.ctrl_blk, i);
+		hw->src_mgr_dsb_src(src_mgr->mgr.ctrl_blk, i);
 
-	((struct hw *)hw)->src_mgr_commit_write(hw, src_mgr->mgr.ctrl_blk);
+	hw->src_mgr_commit_write(hw, src_mgr->mgr.ctrl_blk);
 
 	*rsrc_mgr = src_mgr;
 
@@ -739,7 +741,8 @@
 	}
 	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
 	if (err) {
-		printk(KERN_ERR "ctxfi: Can't meet SRCIMP resource request!\n");
+		dev_err(mgr->card->dev,
+			"Can't meet SRCIMP resource request!\n");
 		goto error1;
 	}
 
@@ -825,7 +828,7 @@
 	return err;
 }
 
-int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrcimp_mgr)
+int srcimp_mgr_create(struct hw *hw, struct srcimp_mgr **rsrcimp_mgr)
 {
 	int err;
 	struct srcimp_mgr *srcimp_mgr;
@@ -857,6 +860,7 @@
 	srcimp_mgr->put_srcimp = put_srcimp_rsc;
 	srcimp_mgr->imap_add = srcimp_imap_add;
 	srcimp_mgr->imap_delete = srcimp_imap_delete;
+	srcimp_mgr->card = hw->card;
 
 	*rsrcimp_mgr = srcimp_mgr;
 
diff --git a/sound/pci/ctxfi/ctsrc.h b/sound/pci/ctxfi/ctsrc.h
index 259366a..da7573c 100644
--- a/sound/pci/ctxfi/ctsrc.h
+++ b/sound/pci/ctxfi/ctsrc.h
@@ -23,6 +23,7 @@
 #include "ctimap.h"
 #include <linux/spinlock.h>
 #include <linux/list.h>
+#include <sound/core.h>
 
 #define SRC_STATE_OFF	0x0
 #define SRC_STATE_INIT	0x4
@@ -85,6 +86,7 @@
 /* Define src manager object */
 struct src_mgr {
 	struct rsc_mgr mgr;	/* Basic resource manager info */
+	struct snd_card *card;	/* pointer to this card */
 	spinlock_t mgr_lock;
 
 	 /* request src resource */
@@ -123,6 +125,7 @@
 
 struct srcimp_mgr {
 	struct rsc_mgr mgr;	/* Basic resource manager info */
+	struct snd_card *card;	/* pointer to this card */
 	spinlock_t mgr_lock;
 	spinlock_t imap_lock;
 	struct list_head imappers;
@@ -140,10 +143,10 @@
 };
 
 /* Constructor and destructor of SRC resource manager */
-int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr);
+int src_mgr_create(struct hw *hw, struct src_mgr **rsrc_mgr);
 int src_mgr_destroy(struct src_mgr *src_mgr);
 /* Constructor and destructor of SRCIMP resource manager */
-int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrc_mgr);
+int srcimp_mgr_create(struct hw *hw, struct srcimp_mgr **rsrc_mgr);
 int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr);
 
 #endif /* CTSRC_H */
diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c
index 6109490..419306e 100644
--- a/sound/pci/ctxfi/ctvmem.c
+++ b/sound/pci/ctxfi/ctvmem.c
@@ -16,6 +16,7 @@
  */
 
 #include "ctvmem.h"
+#include "ctatc.h"
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/io.h>
@@ -29,15 +30,15 @@
  * @size must be page aligned.
  * */
 static struct ct_vm_block *
-get_vm_block(struct ct_vm *vm, unsigned int size)
+get_vm_block(struct ct_vm *vm, unsigned int size, struct ct_atc *atc)
 {
 	struct ct_vm_block *block = NULL, *entry;
 	struct list_head *pos;
 
 	size = CT_PAGE_ALIGN(size);
 	if (size > vm->size) {
-		printk(KERN_ERR "ctxfi: Fail! No sufficient device virtual "
-				  "memory space available!\n");
+		dev_err(atc->card->dev,
+			"Fail! No sufficient device virtual memory space available!\n");
 		return NULL;
 	}
 
@@ -129,11 +130,12 @@
 	unsigned int pte_start;
 	unsigned i, pages;
 	unsigned long *ptp;
+	struct ct_atc *atc = snd_pcm_substream_chip(substream);
 
-	block = get_vm_block(vm, size);
+	block = get_vm_block(vm, size, atc);
 	if (block == NULL) {
-		printk(KERN_ERR "ctxfi: No virtual memory block that is big "
-				  "enough to allocate!\n");
+		dev_err(atc->card->dev,
+			"No virtual memory block that is big enough to allocate!\n");
 		return NULL;
 	}
 
diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c
index 8f8b566..f2f3277 100644
--- a/sound/pci/ctxfi/xfi.c
+++ b/sound/pci/ctxfi/xfi.c
@@ -76,17 +76,18 @@
 	if (err)
 		return err;
 	if ((reference_rate != 48000) && (reference_rate != 44100)) {
-		printk(KERN_ERR "ctxfi: Invalid reference_rate value %u!!!\n",
-		       reference_rate);
-		printk(KERN_ERR "ctxfi: The valid values for reference_rate "
-		       "are 48000 and 44100, Value 48000 is assumed.\n");
+		dev_err(card->dev,
+			"Invalid reference_rate value %u!!!\n",
+			reference_rate);
+		dev_err(card->dev,
+			"The valid values for reference_rate are 48000 and 44100, Value 48000 is assumed.\n");
 		reference_rate = 48000;
 	}
 	if ((multiple != 1) && (multiple != 2) && (multiple != 4)) {
-		printk(KERN_ERR "ctxfi: Invalid multiple value %u!!!\n",
-		       multiple);
-		printk(KERN_ERR "ctxfi: The valid values for multiple are "
-		       "1, 2 and 4, Value 2 is assumed.\n");
+		dev_err(card->dev, "Invalid multiple value %u!!!\n",
+			multiple);
+		dev_err(card->dev,
+			"The valid values for multiple are 1, 2 and 4, Value 2 is assumed.\n");
 		multiple = 2;
 	}
 	err = ct_atc_create(card, pci, reference_rate, multiple,
diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c
index 3f3ef38..874cd76 100644
--- a/sound/pci/emu10k1/emu10k1_callback.c
+++ b/sound/pci/emu10k1/emu10k1_callback.c
@@ -85,6 +85,8 @@
  * get more voice for pcm
  *
  * terminate most inactive voice and give it as a pcm voice.
+ *
+ * voice_lock is already held.
  */
 int
 snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw)
@@ -92,12 +94,10 @@
 	struct snd_emux *emu;
 	struct snd_emux_voice *vp;
 	struct best_voice best[V_END];
-	unsigned long flags;
 	int i;
 
 	emu = hw->synth;
 
-	spin_lock_irqsave(&emu->voice_lock, flags);
 	lookup_voices(emu, hw, best, 1); /* no OFF voices */
 	for (i = 0; i < V_END; i++) {
 		if (best[i].voice >= 0) {
@@ -113,11 +113,9 @@
 			vp->emu->num_voices--;
 			vp->ch = -1;
 			vp->state = SNDRV_EMUX_ST_OFF;
-			spin_unlock_irqrestore(&emu->voice_lock, flags);
 			return ch;
 		}
 	}
-	spin_unlock_irqrestore(&emu->voice_lock, flags);
 
 	/* not found */
 	return -ENOMEM;
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
index 51dea49..fcc5e47 100644
--- a/sound/pci/hda/hda_auto_parser.c
+++ b/sound/pci/hda/hda_auto_parser.c
@@ -57,12 +57,14 @@
 
 
 /* add the found input-pin to the cfg->inputs[] table */
-static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid,
-				   int type)
+static void add_auto_cfg_input_pin(struct hda_codec *codec, struct auto_pin_cfg *cfg,
+				   hda_nid_t nid, int type)
 {
 	if (cfg->num_inputs < AUTO_CFG_MAX_INS) {
 		cfg->inputs[cfg->num_inputs].pin = nid;
 		cfg->inputs[cfg->num_inputs].type = type;
+		cfg->inputs[cfg->num_inputs].has_boost_on_pin =
+			nid_has_volume(codec, nid, HDA_INPUT);
 		cfg->num_inputs++;
 	}
 }
@@ -71,7 +73,12 @@
 {
 	const struct auto_pin_cfg_item *a = ap;
 	const struct auto_pin_cfg_item *b = bp;
-	return (int)(a->type - b->type);
+	if (a->type != b->type)
+		return (int)(a->type - b->type);
+
+	/* In case one has boost and the other one has not,
+	   pick the one with boost first. */
+	return (int)(b->has_boost_on_pin - a->has_boost_on_pin);
 }
 
 /* Reorder the surround channels
@@ -268,16 +275,16 @@
 			cfg->hp_outs++;
 			break;
 		case AC_JACK_MIC_IN:
-			add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC);
+			add_auto_cfg_input_pin(codec, cfg, nid, AUTO_PIN_MIC);
 			break;
 		case AC_JACK_LINE_IN:
-			add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN);
+			add_auto_cfg_input_pin(codec, cfg, nid, AUTO_PIN_LINE_IN);
 			break;
 		case AC_JACK_CD:
-			add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD);
+			add_auto_cfg_input_pin(codec, cfg, nid, AUTO_PIN_CD);
 			break;
 		case AC_JACK_AUX:
-			add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX);
+			add_auto_cfg_input_pin(codec, cfg, nid, AUTO_PIN_AUX);
 			break;
 		case AC_JACK_SPDIF_OUT:
 		case AC_JACK_DIG_OTHER_OUT:
diff --git a/sound/pci/hda/hda_auto_parser.h b/sound/pci/hda/hda_auto_parser.h
index e941f60..2b8e29f 100644
--- a/sound/pci/hda/hda_auto_parser.h
+++ b/sound/pci/hda/hda_auto_parser.h
@@ -38,6 +38,7 @@
 	int type;
 	unsigned int is_headset_mic:1;
 	unsigned int is_headphone_mic:1; /* Mic-only in headphone jack */
+	unsigned int has_boost_on_pin:1;
 };
 
 struct auto_pin_cfg;
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index ec6a7d0..15e0089 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -2002,6 +2002,26 @@
 EXPORT_SYMBOL_GPL(query_amp_caps);
 
 /**
+ * snd_hda_check_amp_caps - query AMP capabilities
+ * @codec: the HD-audio codec
+ * @nid: the NID to query
+ * @dir: either #HDA_INPUT or #HDA_OUTPUT
+ *
+ * Check whether the widget has the given amp capability for the direction.
+ */
+bool snd_hda_check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
+			   int dir, unsigned int bits)
+{
+	if (!nid)
+		return false;
+	if (get_wcaps(codec, nid) & (1 << (dir + 1)))
+		if (query_amp_caps(codec, nid, dir) & bits)
+			return true;
+	return false;
+}
+EXPORT_SYMBOL_GPL(snd_hda_check_amp_caps);
+
+/**
  * snd_hda_override_amp_caps - Override the AMP capabilities
  * @codec: the CODEC to clean up
  * @nid: the NID to clean up
@@ -4817,121 +4837,6 @@
 EXPORT_SYMBOL_GPL(snd_hda_build_pcms);
 
 /**
- * snd_hda_check_board_config - compare the current codec with the config table
- * @codec: the HDA codec
- * @num_configs: number of config enums
- * @models: array of model name strings
- * @tbl: configuration table, terminated by null entries
- *
- * Compares the modelname or PCI subsystem id of the current codec with the
- * given configuration table.  If a matching entry is found, returns its
- * config value (supposed to be 0 or positive).
- *
- * If no entries are matching, the function returns a negative value.
- */
-int snd_hda_check_board_config(struct hda_codec *codec,
-			       int num_configs, const char * const *models,
-			       const struct snd_pci_quirk *tbl)
-{
-	if (codec->modelname && models) {
-		int i;
-		for (i = 0; i < num_configs; i++) {
-			if (models[i] &&
-			    !strcmp(codec->modelname, models[i])) {
-				codec_info(codec, "model '%s' is selected\n",
-					   models[i]);
-				return i;
-			}
-		}
-	}
-
-	if (!codec->bus->pci || !tbl)
-		return -1;
-
-	tbl = snd_pci_quirk_lookup(codec->bus->pci, tbl);
-	if (!tbl)
-		return -1;
-	if (tbl->value >= 0 && tbl->value < num_configs) {
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-		char tmp[10];
-		const char *model = NULL;
-		if (models)
-			model = models[tbl->value];
-		if (!model) {
-			sprintf(tmp, "#%d", tbl->value);
-			model = tmp;
-		}
-		codec_info(codec, "model '%s' is selected for config %x:%x (%s)\n",
-			   model, tbl->subvendor, tbl->subdevice,
-			   (tbl->name ? tbl->name : "Unknown device"));
-#endif
-		return tbl->value;
-	}
-	return -1;
-}
-EXPORT_SYMBOL_GPL(snd_hda_check_board_config);
-
-/**
- * snd_hda_check_board_codec_sid_config - compare the current codec
-					subsystem ID with the
-					config table
-
-	   This is important for Gateway notebooks with SB450 HDA Audio
-	   where the vendor ID of the PCI device is:
-		ATI Technologies Inc SB450 HDA Audio [1002:437b]
-	   and the vendor/subvendor are found only at the codec.
-
- * @codec: the HDA codec
- * @num_configs: number of config enums
- * @models: array of model name strings
- * @tbl: configuration table, terminated by null entries
- *
- * Compares the modelname or PCI subsystem id of the current codec with the
- * given configuration table.  If a matching entry is found, returns its
- * config value (supposed to be 0 or positive).
- *
- * If no entries are matching, the function returns a negative value.
- */
-int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
-			       int num_configs, const char * const *models,
-			       const struct snd_pci_quirk *tbl)
-{
-	const struct snd_pci_quirk *q;
-
-	/* Search for codec ID */
-	for (q = tbl; q->subvendor; q++) {
-		unsigned int mask = 0xffff0000 | q->subdevice_mask;
-		unsigned int id = (q->subdevice | (q->subvendor << 16)) & mask;
-		if ((codec->subsystem_id & mask) == id)
-			break;
-	}
-
-	if (!q->subvendor)
-		return -1;
-
-	tbl = q;
-
-	if (tbl->value >= 0 && tbl->value < num_configs) {
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-		char tmp[10];
-		const char *model = NULL;
-		if (models)
-			model = models[tbl->value];
-		if (!model) {
-			sprintf(tmp, "#%d", tbl->value);
-			model = tmp;
-		}
-		codec_info(codec, "model '%s' is selected for config %x:%x (%s)\n",
-			   model, tbl->subvendor, tbl->subdevice,
-			   (tbl->name ? tbl->name : "Unknown device"));
-#endif
-		return tbl->value;
-	}
-	return -1;
-}
-EXPORT_SYMBOL_GPL(snd_hda_check_board_codec_sid_config);
-
-/**
  * snd_hda_add_new_ctls - create controls from the array
  * @codec: the HDA codec
  * @knew: the array of struct snd_kcontrol_new
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index bbc5a13..9c8820f21 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -687,6 +687,4 @@
 				struct snd_dma_buffer *dmab) {}
 #endif
 
-#define EXPORT_SYMBOL_HDA(sym) EXPORT_SYMBOL_GPL(sym)
-
 #endif /* __SOUND_HDA_CODEC_H */
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index b956449..64220c0 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -31,6 +31,7 @@
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/jack.h>
+#include <sound/tlv.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_auto_parser.h"
@@ -518,18 +519,6 @@
 	return val;
 }
 
-/* check whether the widget has the given amp capability for the direction */
-static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
-			   int dir, unsigned int bits)
-{
-	if (!nid)
-		return false;
-	if (get_wcaps(codec, nid) & (1 << (dir + 1)))
-		if (query_amp_caps(codec, nid, dir) & bits)
-			return true;
-	return false;
-}
-
 static bool same_amp_caps(struct hda_codec *codec, hda_nid_t nid1,
 			  hda_nid_t nid2, int dir)
 {
@@ -539,11 +528,6 @@
 		query_amp_caps(codec, nid2, dir));
 }
 
-#define nid_has_mute(codec, nid, dir) \
-	check_amp_caps(codec, nid, dir, (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE))
-#define nid_has_volume(codec, nid, dir) \
-	check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS)
-
 /* look for a widget suitable for assigning a mute switch in the path */
 static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec,
 				       struct nid_path *path)
@@ -1105,6 +1089,7 @@
  */
 static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path)
 {
+	struct hda_gen_spec *spec = codec->spec;
 	hda_nid_t nid;
 	unsigned int val;
 	int badness = 0;
@@ -1119,6 +1104,8 @@
 	nid = look_for_out_vol_nid(codec, path);
 	if (nid) {
 		val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
+		if (spec->dac_min_mute)
+			val |= HDA_AMP_VAL_MIN_MUTE;
 		if (is_ctl_used(codec, val, NID_PATH_VOL_CTL))
 			badness += BAD_SHARED_VOL;
 		else
@@ -1880,9 +1867,12 @@
 		path = snd_hda_get_path_from_idx(codec, spec->out_paths[0]);
 		if (path)
 			spec->vmaster_nid = look_for_out_vol_nid(codec, path);
-		if (spec->vmaster_nid)
+		if (spec->vmaster_nid) {
 			snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
 						HDA_OUTPUT, spec->vmaster_tlv);
+			if (spec->dac_min_mute)
+				spec->vmaster_tlv[3] |= TLV_DB_SCALE_MUTE;
+		}
 	}
 
 	/* set initial pinctl targets */
@@ -2025,7 +2015,8 @@
  * independent HP controls
  */
 
-static void call_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack);
+static void call_hp_automute(struct hda_codec *codec,
+			     struct hda_jack_callback *jack);
 static int indep_hp_info(struct snd_kcontrol *kcontrol,
 			 struct snd_ctl_elem_info *uinfo)
 {
@@ -3941,7 +3932,8 @@
 }
 
 /* standard HP-automute helper */
-void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
+void snd_hda_gen_hp_automute(struct hda_codec *codec,
+			     struct hda_jack_callback *jack)
 {
 	struct hda_gen_spec *spec = codec->spec;
 	hda_nid_t *pins = spec->autocfg.hp_pins;
@@ -3961,7 +3953,8 @@
 EXPORT_SYMBOL_GPL(snd_hda_gen_hp_automute);
 
 /* standard line-out-automute helper */
-void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
+void snd_hda_gen_line_automute(struct hda_codec *codec,
+			       struct hda_jack_callback *jack)
 {
 	struct hda_gen_spec *spec = codec->spec;
 
@@ -3981,7 +3974,8 @@
 EXPORT_SYMBOL_GPL(snd_hda_gen_line_automute);
 
 /* standard mic auto-switch helper */
-void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *jack)
+void snd_hda_gen_mic_autoswitch(struct hda_codec *codec,
+				struct hda_jack_callback *jack)
 {
 	struct hda_gen_spec *spec = codec->spec;
 	int i;
@@ -4004,7 +3998,8 @@
 EXPORT_SYMBOL_GPL(snd_hda_gen_mic_autoswitch);
 
 /* call appropriate hooks */
-static void call_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
+static void call_hp_automute(struct hda_codec *codec,
+			     struct hda_jack_callback *jack)
 {
 	struct hda_gen_spec *spec = codec->spec;
 	if (spec->hp_automute_hook)
@@ -4014,7 +4009,7 @@
 }
 
 static void call_line_automute(struct hda_codec *codec,
-			       struct hda_jack_tbl *jack)
+			       struct hda_jack_callback *jack)
 {
 	struct hda_gen_spec *spec = codec->spec;
 	if (spec->line_automute_hook)
@@ -4024,7 +4019,7 @@
 }
 
 static void call_mic_autoswitch(struct hda_codec *codec,
-				struct hda_jack_tbl *jack)
+				struct hda_jack_callback *jack)
 {
 	struct hda_gen_spec *spec = codec->spec;
 	if (spec->mic_autoswitch_hook)
@@ -4173,7 +4168,7 @@
 		if (!is_jack_detectable(codec, nid))
 			continue;
 		codec_dbg(codec, "Enable HP auto-muting on NID 0x%x\n", nid);
-		snd_hda_jack_detect_enable_callback(codec, nid, HDA_GEN_HP_EVENT,
+		snd_hda_jack_detect_enable_callback(codec, nid,
 						    call_hp_automute);
 		spec->detect_hp = 1;
 	}
@@ -4186,7 +4181,6 @@
 					continue;
 				codec_dbg(codec, "Enable Line-Out auto-muting on NID 0x%x\n", nid);
 				snd_hda_jack_detect_enable_callback(codec, nid,
-								    HDA_GEN_FRONT_EVENT,
 								    call_line_automute);
 				spec->detect_lo = 1;
 			}
@@ -4228,7 +4222,6 @@
 	for (i = 1; i < spec->am_num_entries; i++)
 		snd_hda_jack_detect_enable_callback(codec,
 						    spec->am_entry[i].pin,
-						    HDA_GEN_MIC_EVENT,
 						    call_mic_autoswitch);
 	return true;
 }
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h
index bb2dea7..61dd515 100644
--- a/sound/pci/hda/hda_generic.h
+++ b/sound/pci/hda/hda_generic.h
@@ -12,12 +12,6 @@
 #ifndef __SOUND_HDA_GENERIC_H
 #define __SOUND_HDA_GENERIC_H
 
-/* unsol event tags */
-enum {
-	HDA_GEN_HP_EVENT = 1, HDA_GEN_FRONT_EVENT, HDA_GEN_MIC_EVENT,
-	HDA_GEN_LAST_EVENT = HDA_GEN_MIC_EVENT
-};
-
 /* table entry for multi-io paths */
 struct hda_multi_io {
 	hda_nid_t pin;		/* multi-io widget pin NID */
@@ -231,6 +225,7 @@
 	unsigned int add_stereo_mix_input:1; /* add aamix as a capture src */
 	unsigned int add_jack_modes:1; /* add i/o jack mode enum ctls */
 	unsigned int power_down_unused:1; /* power down unused widgets */
+	unsigned int dac_min_mute:1; /* minimal = mute for DACs */
 
 	/* other internal flags */
 	unsigned int no_analog:1; /* digital I/O only */
@@ -289,11 +284,11 @@
 
 	/* automute / autoswitch hooks */
 	void (*hp_automute_hook)(struct hda_codec *codec,
-				 struct hda_jack_tbl *tbl);
+				 struct hda_jack_callback *cb);
 	void (*line_automute_hook)(struct hda_codec *codec,
-				   struct hda_jack_tbl *tbl);
+				   struct hda_jack_callback *cb);
 	void (*mic_autoswitch_hook)(struct hda_codec *codec,
-				    struct hda_jack_tbl *tbl);
+				    struct hda_jack_callback *cb);
 };
 
 int snd_hda_gen_spec_init(struct hda_gen_spec *spec);
@@ -325,11 +320,11 @@
 
 /* standard jack event callbacks */
 void snd_hda_gen_hp_automute(struct hda_codec *codec,
-			     struct hda_jack_tbl *jack);
+			     struct hda_jack_callback *jack);
 void snd_hda_gen_line_automute(struct hda_codec *codec,
-			       struct hda_jack_tbl *jack);
+			       struct hda_jack_callback *jack);
 void snd_hda_gen_mic_autoswitch(struct hda_codec *codec,
-				struct hda_jack_tbl *jack);
+				struct hda_jack_callback *jack);
 void snd_hda_gen_update_outputs(struct hda_codec *codec);
 
 #ifdef CONFIG_PM
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index aa302fb..cfcca4c 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -218,6 +218,7 @@
 			 "{Intel, LPT},"
 			 "{Intel, LPT_LP},"
 			 "{Intel, WPT_LP},"
+			 "{Intel, SPT},"
 			 "{Intel, HPT},"
 			 "{Intel, PBG},"
 			 "{Intel, SCH},"
@@ -1998,6 +1999,9 @@
 	/* Wildcat Point-LP */
 	{ PCI_DEVICE(0x8086, 0x9ca0),
 	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+	/* Sunrise Point */
+	{ PCI_DEVICE(0x8086, 0xa170),
+	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
 	/* Haswell */
 	{ PCI_DEVICE(0x8086, 0x0a0c),
 	  .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index 9746d73..f56765ae 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -94,7 +94,7 @@
 /**
  * snd_hda_jack_tbl_new - create a jack-table entry for the given NID
  */
-struct hda_jack_tbl *
+static struct hda_jack_tbl *
 snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid)
 {
 	struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid);
@@ -108,21 +108,24 @@
 	jack->tag = codec->jacktbl.used;
 	return jack;
 }
-EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_new);
 
 void snd_hda_jack_tbl_clear(struct hda_codec *codec)
 {
+	struct hda_jack_tbl *jack = codec->jacktbl.list;
+	int i;
+
+	for (i = 0; i < codec->jacktbl.used; i++, jack++) {
+		struct hda_jack_callback *cb, *next;
 #ifdef CONFIG_SND_HDA_INPUT_JACK
-	/* free jack instances manually when clearing/reconfiguring */
-	if (!codec->bus->shutdown && codec->jacktbl.list) {
-		struct hda_jack_tbl *jack = codec->jacktbl.list;
-		int i;
-		for (i = 0; i < codec->jacktbl.used; i++, jack++) {
-			if (jack->jack)
-				snd_device_free(codec->bus->card, jack->jack);
+		/* free jack instances manually when clearing/reconfiguring */
+		if (!codec->bus->shutdown && jack->jack)
+			snd_device_free(codec->bus->card, jack->jack);
+#endif
+		for (cb = jack->callback; cb; cb = next) {
+			next = cb->next;
+			kfree(cb);
 		}
 	}
-#endif
 	snd_array_free(&codec->jacktbl);
 }
 
@@ -215,33 +218,49 @@
 
 /**
  * snd_hda_jack_detect_enable - enable the jack-detection
+ *
+ * In the case of error, the return value will be a pointer embedded with
+ * errno.  Check and handle the return value appropriately with standard
+ * macros such as @IS_ERR() and @PTR_ERR().
  */
-int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
-					unsigned char action,
-					hda_jack_callback cb)
+struct hda_jack_callback *
+snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
+				    hda_jack_callback_fn func)
 {
-	struct hda_jack_tbl *jack = snd_hda_jack_tbl_new(codec, nid);
+	struct hda_jack_tbl *jack;
+	struct hda_jack_callback *callback = NULL;
+	int err;
+
+	jack = snd_hda_jack_tbl_new(codec, nid);
 	if (!jack)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
+	if (func) {
+		callback = kzalloc(sizeof(*callback), GFP_KERNEL);
+		if (!callback)
+			return ERR_PTR(-ENOMEM);
+		callback->func = func;
+		callback->tbl = jack;
+		callback->next = jack->callback;
+		jack->callback = callback;
+	}
+
 	if (jack->jack_detect)
-		return 0; /* already registered */
+		return callback; /* already registered */
 	jack->jack_detect = 1;
-	if (action)
-		jack->action = action;
-	if (cb)
-		jack->callback = cb;
 	if (codec->jackpoll_interval > 0)
-		return 0; /* No unsol if we're polling instead */
-	return snd_hda_codec_write_cache(codec, nid, 0,
+		return callback; /* No unsol if we're polling instead */
+	err = snd_hda_codec_write_cache(codec, nid, 0,
 					 AC_VERB_SET_UNSOLICITED_ENABLE,
 					 AC_USRSP_EN | jack->tag);
+	if (err < 0)
+		return ERR_PTR(err);
+	return callback;
 }
 EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback);
 
-int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
-			       unsigned char action)
+int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid)
 {
-	return snd_hda_jack_detect_enable_callback(codec, nid, action, NULL);
+	return PTR_ERR_OR_ZERO(snd_hda_jack_detect_enable_callback(codec, nid, NULL));
 }
 EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable);
 
@@ -431,7 +450,7 @@
 		return err;
 
 	if (!phantom_jack)
-		return snd_hda_jack_detect_enable(codec, nid, 0);
+		return snd_hda_jack_detect_enable(codec, nid);
 	return 0;
 }
 
@@ -498,13 +517,17 @@
 static void call_jack_callback(struct hda_codec *codec,
 			       struct hda_jack_tbl *jack)
 {
-	if (jack->callback)
-		jack->callback(codec, jack);
+	struct hda_jack_callback *cb;
+
+	for (cb = jack->callback; cb; cb = cb->next)
+		cb->func(codec, cb);
 	if (jack->gated_jack) {
 		struct hda_jack_tbl *gated =
 			snd_hda_jack_tbl_get(codec, jack->gated_jack);
-		if (gated && gated->callback)
-			gated->callback(codec, gated);
+		if (gated) {
+			for (cb = gated->callback; cb; cb = cb->next)
+				cb->func(codec, cb);
+		}
 	}
 }
 
diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h
index 46e1ea8..13cb375 100644
--- a/sound/pci/hda/hda_jack.h
+++ b/sound/pci/hda/hda_jack.h
@@ -12,17 +12,25 @@
 #ifndef __SOUND_HDA_JACK_H
 #define __SOUND_HDA_JACK_H
 
+#include <linux/err.h>
+
 struct auto_pin_cfg;
 struct hda_jack_tbl;
+struct hda_jack_callback;
 
-typedef void (*hda_jack_callback) (struct hda_codec *, struct hda_jack_tbl *);
+typedef void (*hda_jack_callback_fn) (struct hda_codec *, struct hda_jack_callback *);
+
+struct hda_jack_callback {
+	struct hda_jack_tbl *tbl;
+	hda_jack_callback_fn func;
+	unsigned int private_data;	/* arbitrary data */
+	struct hda_jack_callback *next;
+};
 
 struct hda_jack_tbl {
 	hda_nid_t nid;
-	unsigned char action;		/* event action (0 = none) */
 	unsigned char tag;		/* unsol event tag */
-	unsigned int private_data;	/* arbitrary data */
-	hda_jack_callback callback;
+	struct hda_jack_callback *callback;
 	/* jack-detection stuff */
 	unsigned int pin_sense;		/* cached pin-sense value */
 	unsigned int jack_detect:1;	/* capable of jack-detection? */
@@ -43,34 +51,14 @@
 struct hda_jack_tbl *
 snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag);
 
-struct hda_jack_tbl *
-snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid);
 void snd_hda_jack_tbl_clear(struct hda_codec *codec);
 
-/**
- * snd_hda_jack_get_action - get jack-tbl entry for the tag
- *
- * Call this from the unsol event handler to get the assigned action for the
- * event.  This will mark the dirty flag for the later reporting, too.
- */
-static inline unsigned char
-snd_hda_jack_get_action(struct hda_codec *codec, unsigned int tag)
-{
-	struct hda_jack_tbl *jack = snd_hda_jack_tbl_get_from_tag(codec, tag);
-	if (jack) {
-		jack->jack_dirty = 1;
-		return jack->action;
-	}
-	return 0;
-}
-
 void snd_hda_jack_set_dirty_all(struct hda_codec *codec);
 
-int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
-			       unsigned char action);
-int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
-					unsigned char action,
-					hda_jack_callback cb);
+int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid);
+struct hda_jack_callback *
+snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
+				    hda_jack_callback_fn cb);
 
 int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid,
 				 hda_nid_t gating_nid);
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 364bb41..7eb44e7 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -371,12 +371,6 @@
 /*
  * Misc
  */
-int snd_hda_check_board_config(struct hda_codec *codec, int num_configs,
-			       const char * const *modelnames,
-			       const struct snd_pci_quirk *pci_list);
-int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
-                               int num_configs, const char * const *models,
-                               const struct snd_pci_quirk *tbl);
 int snd_hda_add_new_ctls(struct hda_codec *codec,
 			 const struct snd_kcontrol_new *knew);
 
@@ -609,6 +603,14 @@
 u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid);
 int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid,
 			      unsigned int caps);
+bool snd_hda_check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
+			   int dir, unsigned int bits);
+
+#define nid_has_mute(codec, nid, dir) \
+	snd_hda_check_amp_caps(codec, nid, dir, (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE))
+#define nid_has_volume(codec, nid, dir) \
+	snd_hda_check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS)
+
 
 /* flags for hda_nid_item */
 #define HDA_NID_ITEM_AMP	(1<<0)
diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c
index e207909..9b49f15 100644
--- a/sound/pci/hda/hda_sysfs.c
+++ b/sound/pci/hda/hda_sysfs.c
@@ -514,7 +514,7 @@
 
 static inline int strmatch(const char *a, const char *b)
 {
-	return strnicmp(a, b, strlen(b)) == 0;
+	return strncasecmp(a, b, strlen(b)) == 0;
 }
 
 /* parse the contents after the line "[codec]"
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 5d8455e..4f7ffa8 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -3224,8 +3224,14 @@
 {
 	struct ca0132_spec *spec = container_of(
 		to_delayed_work(work), struct ca0132_spec, unsol_hp_work);
+	struct hda_jack_tbl *jack;
+
 	ca0132_select_out(spec->codec);
-	snd_hda_jack_report_sync(spec->codec);
+	jack = snd_hda_jack_tbl_get(spec->codec, UNSOL_TAG_HP);
+	if (jack) {
+		jack->block_report = 0;
+		snd_hda_jack_report_sync(spec->codec);
+	}
 }
 
 static void ca0132_set_dmic(struct hda_codec *codec, int enable);
@@ -4114,12 +4120,6 @@
 	}
 }
 
-static void ca0132_init_unsol(struct hda_codec *codec)
-{
-	snd_hda_jack_detect_enable(codec, UNSOL_TAG_HP, UNSOL_TAG_HP);
-	snd_hda_jack_detect_enable(codec, UNSOL_TAG_AMIC1, UNSOL_TAG_AMIC1);
-}
-
 static void refresh_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir)
 {
 	unsigned int caps;
@@ -4390,7 +4390,8 @@
 		ca0132_set_dsp_msr(codec, true);
 }
 
-static void ca0132_process_dsp_response(struct hda_codec *codec)
+static void ca0132_process_dsp_response(struct hda_codec *codec,
+					struct hda_jack_callback *callback)
 {
 	struct ca0132_spec *spec = codec->spec;
 
@@ -4403,36 +4404,31 @@
 	dspio_clear_response_queue(codec);
 }
 
-static void ca0132_unsol_event(struct hda_codec *codec, unsigned int res)
+static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
 {
 	struct ca0132_spec *spec = codec->spec;
 
-	if (((res >> AC_UNSOL_RES_TAG_SHIFT) & 0x3f) == UNSOL_TAG_DSP) {
-		ca0132_process_dsp_response(codec);
-	} else {
-		res = snd_hda_jack_get_action(codec,
-				(res >> AC_UNSOL_RES_TAG_SHIFT) & 0x3f);
+	/* 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));
+	cb->tbl->block_report = 1;
+}
 
-		codec_dbg(codec, "snd_hda_jack_get_action: 0x%x\n", res);
+static void amic_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
+{
+	ca0132_select_mic(codec);
+}
 
-		switch (res) {
-		case UNSOL_TAG_HP:
-			/* 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);
-			snd_hda_jack_report_sync(codec);
-			break;
-		default:
-			break;
-		}
-	}
+static void ca0132_init_unsol(struct hda_codec *codec)
+{
+	snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_HP, hp_callback);
+	snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_AMIC1,
+					    amic_callback);
+	snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_DSP,
+					    ca0132_process_dsp_response);
 }
 
 /*
@@ -4443,8 +4439,6 @@
 static struct hda_verb ca0132_base_init_verbs[] = {
 	/*enable ct extension*/
 	{0x15, VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE, 0x1},
-	/*enable DSP node unsol, needed for DSP download*/
-	{0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | UNSOL_TAG_DSP},
 	{}
 };
 
@@ -4561,6 +4555,8 @@
 
 	snd_hda_power_up(codec);
 
+	ca0132_init_unsol(codec);
+
 	ca0132_init_params(codec);
 	ca0132_init_flags(codec);
 	snd_hda_sequence_write(codec, spec->base_init_verbs);
@@ -4583,8 +4579,6 @@
 	for (i = 0; i < spec->num_init_verbs; i++)
 		snd_hda_sequence_write(codec, spec->init_verbs[i]);
 
-	ca0132_init_unsol(codec);
-
 	ca0132_select_out(codec);
 	ca0132_select_mic(codec);
 
@@ -4612,7 +4606,7 @@
 	.build_pcms = ca0132_build_pcms,
 	.init = ca0132_init,
 	.free = ca0132_free,
-	.unsol_event = ca0132_unsol_event,
+	.unsol_event = snd_hda_jack_unsol_event,
 };
 
 static void ca0132_config(struct hda_codec *codec)
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 3db724e..1589c9b 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -135,8 +135,6 @@
 #define CS421X_IDX_DAC_CFG	0x03
 #define CS421X_IDX_SPK_CTL	0x04
 
-#define SPDIF_EVENT		0x04
-
 /* Cirrus Logic CS4213 is like CS4210 but does not have SPDIF input/output */
 #define CS4213_VENDOR_NID	0x09
 
@@ -984,7 +982,7 @@
 }
 
 static void cs4210_spdif_automute(struct hda_codec *codec,
-				  struct hda_jack_tbl *tbl)
+				  struct hda_jack_callback *tbl)
 {
 	struct cs_spec *spec = codec->spec;
 	bool spdif_present = false;
@@ -1019,7 +1017,6 @@
 		if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
 			spec->spdif_detect = 1;
 			snd_hda_jack_detect_enable_callback(codec, nid,
-							    SPDIF_EVENT,
 							    cs4210_spdif_automute);
 		}
 	}
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 47ccb8f..71e4bad 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -26,7 +26,6 @@
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/jack.h>
-#include <sound/tlv.h>
 
 #include "hda_codec.h"
 #include "hda_local.h"
@@ -394,7 +393,8 @@
 }
 
 /* mic_autoswitch hook */
-static void olpc_xo_automic(struct hda_codec *codec, struct hda_jack_tbl *jack)
+static void olpc_xo_automic(struct hda_codec *codec,
+			    struct hda_jack_callback *jack)
 {
 	struct conexant_spec *spec = codec->spec;
 	int saved_cached_write = codec->cached_write;
@@ -752,6 +752,7 @@
 static const struct snd_pci_quirk cxt5066_fixups[] = {
 	SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
 	SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC),
+	SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC),
 	SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
 	SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO),
 	SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
@@ -787,6 +788,7 @@
  */
 static void add_cx5051_fake_mutes(struct hda_codec *codec)
 {
+	struct conexant_spec *spec = codec->spec;
 	static hda_nid_t out_nids[] = {
 		0x10, 0x11, 0
 	};
@@ -796,6 +798,7 @@
 		snd_hda_override_amp_caps(codec, *p, HDA_OUTPUT,
 					  AC_AMPCAP_MIN_MUTE |
 					  query_amp_caps(codec, *p, HDA_OUTPUT));
+	spec->gen.dac_min_mute = true;
 }
 
 static int patch_conexant_auto(struct hda_codec *codec)
@@ -868,11 +871,6 @@
 	if (err < 0)
 		goto error;
 
-	if (codec->vendor_id == 0x14f15051) {
-		/* minimum value is actually mute */
-		spec->gen.vmaster_tlv[3] |= TLV_DB_SCALE_MUTE;
-	}
-
 	codec->patch_ops = cx_auto_patch_ops;
 
 	/* Some laptops with Conexant chips show stalls in S3 resume,
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 99d7d7f..9dc9cf8 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1163,17 +1163,23 @@
 
 static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
 
-static void jack_callback(struct hda_codec *codec, struct hda_jack_tbl *jack)
+static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid)
 {
 	struct hdmi_spec *spec = codec->spec;
-	int pin_idx = pin_nid_to_pin_index(codec, jack->nid);
+	int pin_idx = pin_nid_to_pin_index(codec, nid);
+
 	if (pin_idx < 0)
 		return;
-
 	if (hdmi_present_sense(get_pin(spec, pin_idx), 1))
 		snd_hda_jack_report_sync(codec);
 }
 
+static void jack_callback(struct hda_codec *codec,
+			  struct hda_jack_callback *jack)
+{
+	check_presence_and_report(codec, jack->tbl->nid);
+}
+
 static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
 {
 	int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
@@ -1190,7 +1196,7 @@
 		codec->addr, jack->nid, dev_entry, !!(res & AC_UNSOL_RES_IA),
 		!!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV));
 
-	jack_callback(codec, jack);
+	check_presence_and_report(codec, jack->nid);
 }
 
 static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
@@ -1577,19 +1583,22 @@
 		}
 	}
 
-	if (pin_eld->eld_valid && !eld->eld_valid) {
-		update_eld = true;
+	if (pin_eld->eld_valid != eld->eld_valid)
 		eld_changed = true;
-	}
+
+	if (pin_eld->eld_valid && !eld->eld_valid)
+		update_eld = true;
+
 	if (update_eld) {
 		bool old_eld_valid = pin_eld->eld_valid;
 		pin_eld->eld_valid = eld->eld_valid;
-		eld_changed = pin_eld->eld_size != eld->eld_size ||
+		if (pin_eld->eld_size != eld->eld_size ||
 			      memcmp(pin_eld->eld_buffer, eld->eld_buffer,
-				     eld->eld_size) != 0;
-		if (eld_changed)
+				     eld->eld_size) != 0) {
 			memcpy(pin_eld->eld_buffer, eld->eld_buffer,
 			       eld->eld_size);
+			eld_changed = true;
+		}
 		pin_eld->eld_size = eld->eld_size;
 		pin_eld->info = eld->info;
 
@@ -2165,7 +2174,7 @@
 		hda_nid_t pin_nid = per_pin->pin_nid;
 
 		hdmi_init_pin(codec, pin_nid);
-		snd_hda_jack_detect_enable_callback(codec, pin_nid, pin_nid,
+		snd_hda_jack_detect_enable_callback(codec, pin_nid,
 			codec->jackpoll_interval > 0 ? jack_callback : NULL);
 	}
 	return 0;
@@ -2428,7 +2437,7 @@
 	if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
 		snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE,
 				    AMP_OUT_UNMUTE);
-	snd_hda_jack_detect_enable(codec, pin, pin);
+	snd_hda_jack_detect_enable(codec, pin);
 	return 0;
 }
 
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 1ba22fb..4c35490 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -40,9 +40,6 @@
 /* keep halting ALC5505 DSP, for power saving */
 #define HALT_REALTEK_ALC5505
 
-/* unsol event tags */
-#define ALC_DCVOL_EVENT		0x08
-
 /* for GPIO Poll */
 #define GPIO_MASK	0x03
 
@@ -93,11 +90,6 @@
 	struct alc_customize_define cdefine;
 	unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
 
-	/* inverted dmic fix */
-	unsigned int inv_dmic_fixup:1; /* has inverted digital-mic workaround */
-	unsigned int inv_dmic_muted:1; /* R-ch of inv d-mic is muted? */
-	hda_nid_t inv_dmic_pin;
-
 	/* mute LED for HP laptops, see alc269_fixup_mic_mute_hook() */
 	int mute_led_polarity;
 	hda_nid_t mute_led_nid;
@@ -129,6 +121,83 @@
 };
 
 /*
+ * COEF access helper functions
+ */
+
+static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+			       unsigned int coef_idx)
+{
+	unsigned int val;
+
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
+	val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0);
+	return val;
+}
+
+#define alc_read_coef_idx(codec, coef_idx) \
+	alc_read_coefex_idx(codec, 0x20, coef_idx)
+
+static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+				 unsigned int coef_idx, unsigned int coef_val)
+{
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF, coef_val);
+}
+
+#define alc_write_coef_idx(codec, coef_idx, coef_val) \
+	alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val)
+
+static void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+				  unsigned int coef_idx, unsigned int mask,
+				  unsigned int bits_set)
+{
+	unsigned int val = alc_read_coefex_idx(codec, nid, coef_idx);
+
+	if (val != -1)
+		alc_write_coefex_idx(codec, nid, coef_idx,
+				     (val & ~mask) | bits_set);
+}
+
+#define alc_update_coef_idx(codec, coef_idx, mask, bits_set)	\
+	alc_update_coefex_idx(codec, 0x20, coef_idx, mask, bits_set)
+
+/* a special bypass for COEF 0; read the cached value at the second time */
+static unsigned int alc_get_coef0(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	if (!spec->coef0)
+		spec->coef0 = alc_read_coef_idx(codec, 0);
+	return spec->coef0;
+}
+
+/* coef writes/updates batch */
+struct coef_fw {
+	unsigned char nid;
+	unsigned char idx;
+	unsigned short mask;
+	unsigned short val;
+};
+
+#define UPDATE_COEFEX(_nid, _idx, _mask, _val) \
+	{ .nid = (_nid), .idx = (_idx), .mask = (_mask), .val = (_val) }
+#define WRITE_COEFEX(_nid, _idx, _val) UPDATE_COEFEX(_nid, _idx, -1, _val)
+#define WRITE_COEF(_idx, _val) WRITE_COEFEX(0x20, _idx, _val)
+#define UPDATE_COEF(_idx, _mask, _val) UPDATE_COEFEX(0x20, _idx, _mask, _val)
+
+static void alc_process_coef_fw(struct hda_codec *codec,
+				const struct coef_fw *fw)
+{
+	for (; fw->nid; fw++) {
+		if (fw->mask == (unsigned short)-1)
+			alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val);
+		else
+			alc_update_coefex_idx(codec, fw->nid, fw->idx,
+					      fw->mask, fw->val);
+	}
+}
+
+/*
  * Append the given mixer and verb elements for the later use
  * The mixer array is referred in build_controls(), and init_verbs are
  * called in init().
@@ -173,20 +242,10 @@
 static void alc_fix_pll(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
-	unsigned int val;
 
-	if (!spec->pll_nid)
-		return;
-	snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
-			    spec->pll_coef_idx);
-	val = snd_hda_codec_read(codec, spec->pll_nid, 0,
-				 AC_VERB_GET_PROC_COEF, 0);
-	if (val == -1)
-		return;
-	snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
-			    spec->pll_coef_idx);
-	snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
-			    val & ~(1 << spec->pll_coef_bit));
+	if (spec->pll_nid)
+		alc_update_coefex_idx(codec, spec->pll_nid, spec->pll_coef_idx,
+				      1 << spec->pll_coef_bit, 0);
 }
 
 static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
@@ -200,7 +259,8 @@
 }
 
 /* update the master volume per volume-knob's unsol event */
-static void alc_update_knob_master(struct hda_codec *codec, struct hda_jack_tbl *jack)
+static void alc_update_knob_master(struct hda_codec *codec,
+				   struct hda_jack_callback *jack)
 {
 	unsigned int val;
 	struct snd_kcontrol *kctl;
@@ -212,7 +272,7 @@
 	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
 	if (!uctl)
 		return;
-	val = snd_hda_codec_read(codec, jack->nid, 0,
+	val = snd_hda_codec_read(codec, jack->tbl->nid, 0,
 				 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
 	val &= HDA_AMP_VOLMASK;
 	uctl->value.integer.value[0] = val;
@@ -231,30 +291,18 @@
 /* additional initialization for ALC888 variants */
 static void alc888_coef_init(struct hda_codec *codec)
 {
-	unsigned int tmp;
-
-	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
-	tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
-	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
-	if ((tmp & 0xf0) == 0x20)
+	if (alc_get_coef0(codec) == 0x20)
 		/* alc888S-VC */
-		snd_hda_codec_read(codec, 0x20, 0,
-				   AC_VERB_SET_PROC_COEF, 0x830);
+		alc_write_coef_idx(codec, 7, 0x830);
 	 else
 		 /* alc888-VB */
-		 snd_hda_codec_read(codec, 0x20, 0,
-				    AC_VERB_SET_PROC_COEF, 0x3030);
+		alc_write_coef_idx(codec, 7, 0x3030);
 }
 
 /* additional initialization for ALC889 variants */
 static void alc889_coef_init(struct hda_codec *codec)
 {
-	unsigned int tmp;
-
-	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
-	tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
-	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
-	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
+	alc_update_coef_idx(codec, 7, 0, 0x2010);
 }
 
 /* turn on/off EAPD control (only if available) */
@@ -295,8 +343,6 @@
 /* generic EAPD initialization */
 static void alc_auto_init_amp(struct hda_codec *codec, int type)
 {
-	unsigned int tmp;
-
 	alc_auto_setup_eapd(codec, true);
 	switch (type) {
 	case ALC_INIT_GPIO1:
@@ -311,15 +357,7 @@
 	case ALC_INIT_DEFAULT:
 		switch (codec->vendor_id) {
 		case 0x10ec0260:
-			snd_hda_codec_write(codec, 0x1a, 0,
-					    AC_VERB_SET_COEF_INDEX, 7);
-			tmp = snd_hda_codec_read(codec, 0x1a, 0,
-						 AC_VERB_GET_PROC_COEF, 0);
-			snd_hda_codec_write(codec, 0x1a, 0,
-					    AC_VERB_SET_COEF_INDEX, 7);
-			snd_hda_codec_write(codec, 0x1a, 0,
-					    AC_VERB_SET_PROC_COEF,
-					    tmp | 0x2010);
+			alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x2010);
 			break;
 		case 0x10ec0262:
 		case 0x10ec0880:
@@ -337,15 +375,7 @@
 #if 0 /* XXX: This may cause the silent output on speaker on some machines */
 		case 0x10ec0267:
 		case 0x10ec0268:
-			snd_hda_codec_write(codec, 0x20, 0,
-					    AC_VERB_SET_COEF_INDEX, 7);
-			tmp = snd_hda_codec_read(codec, 0x20, 0,
-						 AC_VERB_GET_PROC_COEF, 0);
-			snd_hda_codec_write(codec, 0x20, 0,
-					    AC_VERB_SET_COEF_INDEX, 7);
-			snd_hda_codec_write(codec, 0x20, 0,
-					    AC_VERB_SET_PROC_COEF,
-					    tmp | 0x3000);
+			alc_update_coef_idx(codec, 7, 0, 0x3000);
 			break;
 #endif /* XXX */
 		}
@@ -588,190 +618,14 @@
 }
 
 /*
- * COEF access helper functions
  */
 
-static int alc_read_coefex_idx(struct hda_codec *codec,
-					hda_nid_t nid,
-					unsigned int coef_idx)
-{
-	unsigned int val;
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX,
-		    		coef_idx);
-	val = snd_hda_codec_read(codec, nid, 0,
-			 	AC_VERB_GET_PROC_COEF, 0);
-	return val;
-}
-
-#define alc_read_coef_idx(codec, coef_idx) \
-	alc_read_coefex_idx(codec, 0x20, coef_idx)
-
-static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
-							unsigned int coef_idx,
-							unsigned int coef_val)
-{
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX,
-			    coef_idx);
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF,
-			    coef_val);
-}
-
-#define alc_write_coef_idx(codec, coef_idx, coef_val) \
-	alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val)
-
-/* a special bypass for COEF 0; read the cached value at the second time */
-static unsigned int alc_get_coef0(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-	if (!spec->coef0)
-		spec->coef0 = alc_read_coef_idx(codec, 0);
-	return spec->coef0;
-}
-
-/*
- */
-
-static hda_nid_t get_adc_nid(struct hda_codec *codec, int adc_idx, int imux_idx)
-{
-	struct hda_gen_spec *spec = codec->spec;
-	if (spec->dyn_adc_switch)
-		adc_idx = spec->dyn_adc_idx[imux_idx];
-	return spec->adc_nids[adc_idx];
-}
-
-static void alc_inv_dmic_sync_adc(struct hda_codec *codec, int adc_idx)
-{
-	struct alc_spec *spec = codec->spec;
-	struct hda_input_mux *imux = &spec->gen.input_mux;
-	struct nid_path *path;
-	hda_nid_t nid;
-	int i, dir, parm;
-	unsigned int val;
-
-	for (i = 0; i < imux->num_items; i++) {
-		if (spec->gen.imux_pins[i] == spec->inv_dmic_pin)
-			break;
-	}
-	if (i >= imux->num_items)
-		return;
-
-	path = snd_hda_get_nid_path(codec, spec->inv_dmic_pin,
-				    get_adc_nid(codec, adc_idx, i));
-	val = path->ctls[NID_PATH_MUTE_CTL];
-	if (!val)
-		return;
-	nid = get_amp_nid_(val);
-	dir = get_amp_direction_(val);
-	parm = AC_AMP_SET_RIGHT |
-		(dir == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT);
-
-	/* flush all cached amps at first */
-	snd_hda_codec_flush_cache(codec);
-
-	/* we care only right channel */
-	val = snd_hda_codec_amp_read(codec, nid, 1, dir, 0);
-	if (val & 0x80) /* if already muted, we don't need to touch */
-		return;
-	val |= 0x80;
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-			    parm | val);
-}
-
-/*
- * Inverted digital-mic handling
- *
- * First off, it's a bit tricky.  The "Inverted Internal Mic Capture Switch"
- * gives the additional mute only to the right channel of the digital mic
- * capture stream.  This is a workaround for avoiding the almost silence
- * by summing the stereo stream from some (known to be ForteMedia)
- * digital mic unit.
- *
- * The logic is to call alc_inv_dmic_sync() after each action (possibly)
- * modifying ADC amp.  When the mute flag is set, it mutes the R-channel
- * without caching so that the cache can still keep the original value.
- * The cached value is then restored when the flag is set off or any other
- * than d-mic is used as the current input source.
- */
-static void alc_inv_dmic_sync(struct hda_codec *codec, bool force)
-{
-	struct alc_spec *spec = codec->spec;
-	int src, nums;
-
-	if (!spec->inv_dmic_fixup)
-		return;
-	if (!spec->inv_dmic_muted && !force)
-		return;
-	nums = spec->gen.dyn_adc_switch ? 1 : spec->gen.num_adc_nids;
-	for (src = 0; src < nums; src++) {
-		bool dmic_fixup = false;
-
-		if (spec->inv_dmic_muted &&
-		    spec->gen.imux_pins[spec->gen.cur_mux[src]] == spec->inv_dmic_pin)
-			dmic_fixup = true;
-		if (!dmic_fixup && !force)
-			continue;
-		alc_inv_dmic_sync_adc(codec, src);
-	}
-}
-
-static void alc_inv_dmic_hook(struct hda_codec *codec,
-			      struct snd_kcontrol *kcontrol,
-			      struct snd_ctl_elem_value *ucontrol)
-{
-	alc_inv_dmic_sync(codec, false);
-}
-
-static int alc_inv_dmic_sw_get(struct snd_kcontrol *kcontrol,
-			       struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct alc_spec *spec = codec->spec;
-
-	ucontrol->value.integer.value[0] = !spec->inv_dmic_muted;
-	return 0;
-}
-
-static int alc_inv_dmic_sw_put(struct snd_kcontrol *kcontrol,
-			       struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct alc_spec *spec = codec->spec;
-	unsigned int val = !ucontrol->value.integer.value[0];
-
-	if (val == spec->inv_dmic_muted)
-		return 0;
-	spec->inv_dmic_muted = val;
-	alc_inv_dmic_sync(codec, true);
-	return 0;
-}
-
-static const struct snd_kcontrol_new alc_inv_dmic_sw = {
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = "Inverted Internal Mic Capture Switch",
-	.info = snd_ctl_boolean_mono_info,
-	.get = alc_inv_dmic_sw_get,
-	.put = alc_inv_dmic_sw_put,
-};
-
-static int alc_add_inv_dmic_mixer(struct hda_codec *codec, hda_nid_t nid)
+static void alc_fixup_inv_dmic(struct hda_codec *codec,
+			       const struct hda_fixup *fix, int action)
 {
 	struct alc_spec *spec = codec->spec;
 
-	if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &alc_inv_dmic_sw))
-		return -ENOMEM;
-	spec->inv_dmic_fixup = 1;
-	spec->inv_dmic_muted = 0;
-	spec->inv_dmic_pin = nid;
-	spec->gen.cap_sync_hook = alc_inv_dmic_hook;
-	return 0;
-}
-
-/* typically the digital mic is put at node 0x12 */
-static void alc_fixup_inv_dmic_0x12(struct hda_codec *codec,
-				    const struct hda_fixup *fix, int action)
-{
-	if (action == HDA_FIXUP_ACT_PROBE)
-		alc_add_inv_dmic_mixer(codec, 0x12);
+	spec->gen.inv_dmic_split = 1;
 }
 
 
@@ -880,7 +734,6 @@
 	codec->patch_ops.init(codec);
 	snd_hda_codec_resume_amp(codec);
 	snd_hda_codec_resume_cache(codec);
-	alc_inv_dmic_sync(codec, true);
 	hda_call_check_power_status(codec, 0x01);
 	return 0;
 }
@@ -1134,7 +987,8 @@
 				  const struct hda_fixup *fix, int action)
 {
 	if (action == HDA_FIXUP_ACT_PROBE)
-		snd_hda_jack_detect_enable_callback(codec, 0x21, ALC_DCVOL_EVENT, alc_update_knob_master);
+		snd_hda_jack_detect_enable_callback(codec, 0x21,
+						    alc_update_knob_master);
 }
 
 static const struct hda_fixup alc880_fixups[] = {
@@ -1597,7 +1451,7 @@
 		spec->gen.detect_hp = 1;
 		spec->gen.automute_speaker = 1;
 		spec->gen.autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
-		snd_hda_jack_detect_enable_callback(codec, 0x0f, HDA_GEN_HP_EVENT,
+		snd_hda_jack_detect_enable_callback(codec, 0x0f,
 						    snd_hda_gen_hp_automute);
 		snd_hda_add_verbs(codec, alc_gpio1_init_verbs);
 	}
@@ -2222,7 +2076,7 @@
 	},
 	[ALC882_FIXUP_INV_DMIC] = {
 		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_inv_dmic_0x12,
+		.v.func = alc_fixup_inv_dmic,
 	},
 	[ALC882_FIXUP_NO_PRIMARY_HP] = {
 		.type = HDA_FIXUP_FUNC,
@@ -2473,7 +2327,7 @@
 	},
 	[ALC262_FIXUP_INV_DMIC] = {
 		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_inv_dmic_0x12,
+		.v.func = alc_fixup_inv_dmic,
 	},
 	[ALC262_FIXUP_INTEL_BAYLEYBAY] = {
 		.type = HDA_FIXUP_FUNC,
@@ -2517,13 +2371,7 @@
 	/* pshou 07/11/05  set a zero PCM sample to DAC when FIFO is
 	 * under-run
 	 */
-	{
-	int tmp;
-	snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
-	tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
-	snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
-	snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
-	}
+	alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x80);
 #endif
 	alc_fix_pll_init(codec, 0x20, 0x0a, 10);
 
@@ -2592,7 +2440,7 @@
 static const struct hda_fixup alc268_fixups[] = {
 	[ALC268_FIXUP_INV_DMIC] = {
 		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_inv_dmic_0x12,
+		.v.func = alc_fixup_inv_dmic,
 	},
 	[ALC268_FIXUP_HP_EAPD] = {
 		.type = HDA_FIXUP_VERBS,
@@ -2809,14 +2657,7 @@
 
 static void alc269vb_toggle_power_output(struct hda_codec *codec, int power_up)
 {
-	int val = alc_read_coef_idx(codec, 0x04);
-	if (val == -1)
-		return;
-	if (power_up)
-		val |= 1 << 11;
-	else
-		val &= ~(1 << 11);
-	alc_write_coef_idx(codec, 0x04, val);
+	alc_update_coef_idx(codec, 0x04, 1 << 11, power_up ? (1 << 11) : 0);
 }
 
 static void alc269_shutup(struct hda_codec *codec)
@@ -2832,79 +2673,42 @@
 	snd_hda_shutup_pins(codec);
 }
 
+static struct coef_fw alc282_coefs[] = {
+	WRITE_COEF(0x03, 0x0002), /* Power Down Control */
+	WRITE_COEF(0x05, 0x0700), /* FIFO and filter clock */
+	WRITE_COEF(0x07, 0x0200), /* DMIC control */
+	UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */
+	UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */
+	WRITE_COEF(0x0a, 0xcccc), /* JD offset1 */
+	WRITE_COEF(0x0b, 0xcccc), /* JD offset2 */
+	WRITE_COEF(0x0e, 0x6e00), /* LDO1/2/3, DAC/ADC */
+	UPDATE_COEF(0x0f, 0xf800, 0x1000), /* JD */
+	UPDATE_COEF(0x10, 0xfc00, 0x0c00), /* Capless */
+	WRITE_COEF(0x6f, 0x0), /* Class D test 4 */
+	UPDATE_COEF(0x0c, 0xfe00, 0), /* IO power down directly */
+	WRITE_COEF(0x34, 0xa0c0), /* ANC */
+	UPDATE_COEF(0x16, 0x0008, 0), /* AGC MUX */
+	UPDATE_COEF(0x1d, 0x00e0, 0), /* DAC simple content protection */
+	UPDATE_COEF(0x1f, 0x00e0, 0), /* ADC simple content protection */
+	WRITE_COEF(0x21, 0x8804), /* DAC ADC Zero Detection */
+	WRITE_COEF(0x63, 0x2902), /* PLL */
+	WRITE_COEF(0x68, 0xa080), /* capless control 2 */
+	WRITE_COEF(0x69, 0x3400), /* capless control 3 */
+	WRITE_COEF(0x6a, 0x2f3e), /* capless control 4 */
+	WRITE_COEF(0x6b, 0x0), /* capless control 5 */
+	UPDATE_COEF(0x6d, 0x0fff, 0x0900), /* class D test 2 */
+	WRITE_COEF(0x6e, 0x110a), /* class D test 3 */
+	UPDATE_COEF(0x70, 0x00f8, 0x00d8), /* class D test 5 */
+	WRITE_COEF(0x71, 0x0014), /* class D test 6 */
+	WRITE_COEF(0x72, 0xc2ba), /* classD OCP */
+	UPDATE_COEF(0x77, 0x0f80, 0), /* classD pure DC test */
+	WRITE_COEF(0x6c, 0xfc06), /* Class D amp control */
+	{}
+};
+
 static void alc282_restore_default_value(struct hda_codec *codec)
 {
-	int val;
-
-	/* Power Down Control */
-	alc_write_coef_idx(codec, 0x03, 0x0002);
-	/* FIFO and filter clock */
-	alc_write_coef_idx(codec, 0x05, 0x0700);
-	/* DMIC control */
-	alc_write_coef_idx(codec, 0x07, 0x0200);
-	/* Analog clock */
-	val = alc_read_coef_idx(codec, 0x06);
-	alc_write_coef_idx(codec, 0x06, (val & ~0x00f0) | 0x0);
-	/* JD */
-	val = alc_read_coef_idx(codec, 0x08);
-	alc_write_coef_idx(codec, 0x08, (val & ~0xfffc) | 0x0c2c);
-	/* JD offset1 */
-	alc_write_coef_idx(codec, 0x0a, 0xcccc);
-	/* JD offset2 */
-	alc_write_coef_idx(codec, 0x0b, 0xcccc);
-	/* LDO1/2/3, DAC/ADC */
-	alc_write_coef_idx(codec, 0x0e, 0x6e00);
-	/* JD */
-	val = alc_read_coef_idx(codec, 0x0f);
-	alc_write_coef_idx(codec, 0x0f, (val & ~0xf800) | 0x1000);
-	/* Capless */
-	val = alc_read_coef_idx(codec, 0x10);
-	alc_write_coef_idx(codec, 0x10, (val & ~0xfc00) | 0x0c00);
-	/* Class D test 4 */
-	alc_write_coef_idx(codec, 0x6f, 0x0);
-	/* IO power down directly */
-	val = alc_read_coef_idx(codec, 0x0c);
-	alc_write_coef_idx(codec, 0x0c, (val & ~0xfe00) | 0x0);
-	/* ANC */
-	alc_write_coef_idx(codec, 0x34, 0xa0c0);
-	/* AGC MUX */
-	val = alc_read_coef_idx(codec, 0x16);
-	alc_write_coef_idx(codec, 0x16, (val & ~0x0008) | 0x0);
-	/* DAC simple content protection */
-	val = alc_read_coef_idx(codec, 0x1d);
-	alc_write_coef_idx(codec, 0x1d, (val & ~0x00e0) | 0x0);
-	/* ADC simple content protection */
-	val = alc_read_coef_idx(codec, 0x1f);
-	alc_write_coef_idx(codec, 0x1f, (val & ~0x00e0) | 0x0);
-	/* DAC ADC Zero Detection */
-	alc_write_coef_idx(codec, 0x21, 0x8804);
-	/* PLL */
-	alc_write_coef_idx(codec, 0x63, 0x2902);
-	/* capless control 2 */
-	alc_write_coef_idx(codec, 0x68, 0xa080);
-	/* capless control 3 */
-	alc_write_coef_idx(codec, 0x69, 0x3400);
-	/* capless control 4 */
-	alc_write_coef_idx(codec, 0x6a, 0x2f3e);
-	/* capless control 5 */
-	alc_write_coef_idx(codec, 0x6b, 0x0);
-	/* class D test 2 */
-	val = alc_read_coef_idx(codec, 0x6d);
-	alc_write_coef_idx(codec, 0x6d, (val & ~0x0fff) | 0x0900);
-	/* class D test 3 */
-	alc_write_coef_idx(codec, 0x6e, 0x110a);
-	/* class D test 5 */
-	val = alc_read_coef_idx(codec, 0x70);
-	alc_write_coef_idx(codec, 0x70, (val & ~0x00f8) | 0x00d8);
-	/* class D test 6 */
-	alc_write_coef_idx(codec, 0x71, 0x0014);
-	/* classD OCP */
-	alc_write_coef_idx(codec, 0x72, 0xc2ba);
-	/* classD pure DC test */
-	val = alc_read_coef_idx(codec, 0x77);
-	alc_write_coef_idx(codec, 0x77, (val & ~0x0f80) | 0x0);
-	/* Class D amp control */
-	alc_write_coef_idx(codec, 0x6c, 0xfc06);
+	alc_process_coef_fw(codec, alc282_coefs);
 }
 
 static void alc282_init(struct hda_codec *codec)
@@ -2980,87 +2784,45 @@
 	alc_write_coef_idx(codec, 0x78, coef78);
 }
 
+static struct coef_fw alc283_coefs[] = {
+	WRITE_COEF(0x03, 0x0002), /* Power Down Control */
+	WRITE_COEF(0x05, 0x0700), /* FIFO and filter clock */
+	WRITE_COEF(0x07, 0x0200), /* DMIC control */
+	UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */
+	UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */
+	WRITE_COEF(0x0a, 0xcccc), /* JD offset1 */
+	WRITE_COEF(0x0b, 0xcccc), /* JD offset2 */
+	WRITE_COEF(0x0e, 0x6fc0), /* LDO1/2/3, DAC/ADC */
+	UPDATE_COEF(0x0f, 0xf800, 0x1000), /* JD */
+	UPDATE_COEF(0x10, 0xfc00, 0x0c00), /* Capless */
+	WRITE_COEF(0x3a, 0x0), /* Class D test 4 */
+	UPDATE_COEF(0x0c, 0xfe00, 0x0), /* IO power down directly */
+	WRITE_COEF(0x22, 0xa0c0), /* ANC */
+	UPDATE_COEFEX(0x53, 0x01, 0x000f, 0x0008), /* AGC MUX */
+	UPDATE_COEF(0x1d, 0x00e0, 0), /* DAC simple content protection */
+	UPDATE_COEF(0x1f, 0x00e0, 0), /* ADC simple content protection */
+	WRITE_COEF(0x21, 0x8804), /* DAC ADC Zero Detection */
+	WRITE_COEF(0x2e, 0x2902), /* PLL */
+	WRITE_COEF(0x33, 0xa080), /* capless control 2 */
+	WRITE_COEF(0x34, 0x3400), /* capless control 3 */
+	WRITE_COEF(0x35, 0x2f3e), /* capless control 4 */
+	WRITE_COEF(0x36, 0x0), /* capless control 5 */
+	UPDATE_COEF(0x38, 0x0fff, 0x0900), /* class D test 2 */
+	WRITE_COEF(0x39, 0x110a), /* class D test 3 */
+	UPDATE_COEF(0x3b, 0x00f8, 0x00d8), /* class D test 5 */
+	WRITE_COEF(0x3c, 0x0014), /* class D test 6 */
+	WRITE_COEF(0x3d, 0xc2ba), /* classD OCP */
+	UPDATE_COEF(0x42, 0x0f80, 0x0), /* classD pure DC test */
+	WRITE_COEF(0x49, 0x0), /* test mode */
+	UPDATE_COEF(0x40, 0xf800, 0x9800), /* Class D DC enable */
+	UPDATE_COEF(0x42, 0xf000, 0x2000), /* DC offset */
+	WRITE_COEF(0x37, 0xfc06), /* Class D amp control */
+	{}
+};
+
 static void alc283_restore_default_value(struct hda_codec *codec)
 {
-	int val;
-
-	/* Power Down Control */
-	alc_write_coef_idx(codec, 0x03, 0x0002);
-	/* FIFO and filter clock */
-	alc_write_coef_idx(codec, 0x05, 0x0700);
-	/* DMIC control */
-	alc_write_coef_idx(codec, 0x07, 0x0200);
-	/* Analog clock */
-	val = alc_read_coef_idx(codec, 0x06);
-	alc_write_coef_idx(codec, 0x06, (val & ~0x00f0) | 0x0);
-	/* JD */
-	val = alc_read_coef_idx(codec, 0x08);
-	alc_write_coef_idx(codec, 0x08, (val & ~0xfffc) | 0x0c2c);
-	/* JD offset1 */
-	alc_write_coef_idx(codec, 0x0a, 0xcccc);
-	/* JD offset2 */
-	alc_write_coef_idx(codec, 0x0b, 0xcccc);
-	/* LDO1/2/3, DAC/ADC */
-	alc_write_coef_idx(codec, 0x0e, 0x6fc0);
-	/* JD */
-	val = alc_read_coef_idx(codec, 0x0f);
-	alc_write_coef_idx(codec, 0x0f, (val & ~0xf800) | 0x1000);
-	/* Capless */
-	val = alc_read_coef_idx(codec, 0x10);
-	alc_write_coef_idx(codec, 0x10, (val & ~0xfc00) | 0x0c00);
-	/* Class D test 4 */
-	alc_write_coef_idx(codec, 0x3a, 0x0);
-	/* IO power down directly */
-	val = alc_read_coef_idx(codec, 0x0c);
-	alc_write_coef_idx(codec, 0x0c, (val & ~0xfe00) | 0x0);
-	/* ANC */
-	alc_write_coef_idx(codec, 0x22, 0xa0c0);
-	/* AGC MUX */
-	val = alc_read_coefex_idx(codec, 0x53, 0x01);
-	alc_write_coefex_idx(codec, 0x53, 0x01, (val & ~0x000f) | 0x0008);
-	/* DAC simple content protection */
-	val = alc_read_coef_idx(codec, 0x1d);
-	alc_write_coef_idx(codec, 0x1d, (val & ~0x00e0) | 0x0);
-	/* ADC simple content protection */
-	val = alc_read_coef_idx(codec, 0x1f);
-	alc_write_coef_idx(codec, 0x1f, (val & ~0x00e0) | 0x0);
-	/* DAC ADC Zero Detection */
-	alc_write_coef_idx(codec, 0x21, 0x8804);
-	/* PLL */
-	alc_write_coef_idx(codec, 0x2e, 0x2902);
-	/* capless control 2 */
-	alc_write_coef_idx(codec, 0x33, 0xa080);
-	/* capless control 3 */
-	alc_write_coef_idx(codec, 0x34, 0x3400);
-	/* capless control 4 */
-	alc_write_coef_idx(codec, 0x35, 0x2f3e);
-	/* capless control 5 */
-	alc_write_coef_idx(codec, 0x36, 0x0);
-	/* class D test 2 */
-	val = alc_read_coef_idx(codec, 0x38);
-	alc_write_coef_idx(codec, 0x38, (val & ~0x0fff) | 0x0900);
-	/* class D test 3 */
-	alc_write_coef_idx(codec, 0x39, 0x110a);
-	/* class D test 5 */
-	val = alc_read_coef_idx(codec, 0x3b);
-	alc_write_coef_idx(codec, 0x3b, (val & ~0x00f8) | 0x00d8);
-	/* class D test 6 */
-	alc_write_coef_idx(codec, 0x3c, 0x0014);
-	/* classD OCP */
-	alc_write_coef_idx(codec, 0x3d, 0xc2ba);
-	/* classD pure DC test */
-	val = alc_read_coef_idx(codec, 0x42);
-	alc_write_coef_idx(codec, 0x42, (val & ~0x0f80) | 0x0);
-	/* test mode */
-	alc_write_coef_idx(codec, 0x49, 0x0);
-	/* Class D DC enable */
-	val = alc_read_coef_idx(codec, 0x40);
-	alc_write_coef_idx(codec, 0x40, (val & ~0xf800) | 0x9800);
-	/* DC offset */
-	val = alc_read_coef_idx(codec, 0x42);
-	alc_write_coef_idx(codec, 0x42, (val & ~0xf000) | 0x2000);
-	/* Class D amp control */
-	alc_write_coef_idx(codec, 0x37, 0xfc06);
+	alc_process_coef_fw(codec, alc283_coefs);
 }
 
 static void alc283_init(struct hda_codec *codec)
@@ -3068,7 +2830,6 @@
 	struct alc_spec *spec = codec->spec;
 	hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
 	bool hp_pin_sense;
-	int val;
 
 	if (!spec->gen.autocfg.hp_outs) {
 		if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT)
@@ -3098,8 +2859,7 @@
 		msleep(85);
 	/* Index 0x46 Combo jack auto switch control 2 */
 	/* 3k pull low control for Headset jack. */
-	val = alc_read_coef_idx(codec, 0x46);
-	alc_write_coef_idx(codec, 0x46, val & ~(3 << 12));
+	alc_update_coef_idx(codec, 0x46, 3 << 12, 0);
 	/* Headphone capless set to normal mode */
 	alc_write_coef_idx(codec, 0x43, 0x9614);
 }
@@ -3109,7 +2869,6 @@
 	struct alc_spec *spec = codec->spec;
 	hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
 	bool hp_pin_sense;
-	int val;
 
 	if (!spec->gen.autocfg.hp_outs) {
 		if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT)
@@ -3125,6 +2884,9 @@
 
 	alc_write_coef_idx(codec, 0x43, 0x9004);
 
+	/*depop hp during suspend*/
+	alc_write_coef_idx(codec, 0x06, 0x2100);
+
 	snd_hda_codec_write(codec, hp_pin, 0,
 			    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
 
@@ -3134,8 +2896,7 @@
 	snd_hda_codec_write(codec, hp_pin, 0,
 			    AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
 
-	val = alc_read_coef_idx(codec, 0x46);
-	alc_write_coef_idx(codec, 0x46, val | (3 << 12));
+	alc_update_coef_idx(codec, 0x46, 0, 3 << 12);
 
 	if (hp_pin_sense)
 		msleep(100);
@@ -3268,7 +3029,6 @@
 
 	snd_hda_codec_resume_amp(codec);
 	snd_hda_codec_resume_cache(codec);
-	alc_inv_dmic_sync(codec, true);
 	hda_call_check_power_status(codec, 0x01);
 
 	/* on some machine, the BIOS will clear the codec gpio data when enter
@@ -3298,12 +3058,8 @@
 static void alc269_fixup_hweq(struct hda_codec *codec,
 			       const struct hda_fixup *fix, int action)
 {
-	int coef;
-
-	if (action != HDA_FIXUP_ACT_INIT)
-		return;
-	coef = alc_read_coef_idx(codec, 0x1e);
-	alc_write_coef_idx(codec, 0x1e, coef | 0x80);
+	if (action == HDA_FIXUP_ACT_INIT)
+		alc_update_coef_idx(codec, 0x1e, 0, 0x80);
 }
 
 static void alc269_fixup_headset_mic(struct hda_codec *codec,
@@ -3351,32 +3107,21 @@
 static void alc269_fixup_stereo_dmic(struct hda_codec *codec,
 				     const struct hda_fixup *fix, int action)
 {
-	int coef;
-
-	if (action != HDA_FIXUP_ACT_INIT)
-		return;
 	/* The digital-mic unit sends PDM (differential signal) instead of
 	 * the standard PCM, thus you can't record a valid mono stream as is.
 	 * Below is a workaround specific to ALC269 to control the dmic
 	 * signal source as mono.
 	 */
-	coef = alc_read_coef_idx(codec, 0x07);
-	alc_write_coef_idx(codec, 0x07, coef | 0x80);
+	if (action == HDA_FIXUP_ACT_INIT)
+		alc_update_coef_idx(codec, 0x07, 0, 0x80);
 }
 
 static void alc269_quanta_automute(struct hda_codec *codec)
 {
 	snd_hda_gen_update_outputs(codec);
 
-	snd_hda_codec_write(codec, 0x20, 0,
-			AC_VERB_SET_COEF_INDEX, 0x0c);
-	snd_hda_codec_write(codec, 0x20, 0,
-			AC_VERB_SET_PROC_COEF, 0x680);
-
-	snd_hda_codec_write(codec, 0x20, 0,
-			AC_VERB_SET_COEF_INDEX, 0x0c);
-	snd_hda_codec_write(codec, 0x20, 0,
-			AC_VERB_SET_PROC_COEF, 0x480);
+	alc_write_coef_idx(codec, 0x0c, 0x680);
+	alc_write_coef_idx(codec, 0x0c, 0x480);
 }
 
 static void alc269_fixup_quanta_mute(struct hda_codec *codec,
@@ -3389,7 +3134,7 @@
 }
 
 static void alc269_x101_hp_automute_hook(struct hda_codec *codec,
-					 struct hda_jack_tbl *jack)
+					 struct hda_jack_callback *jack)
 {
 	struct alc_spec *spec = codec->spec;
 	int vref;
@@ -3622,61 +3367,62 @@
 
 static void alc_headset_mode_unplugged(struct hda_codec *codec)
 {
-	int val;
+	static struct coef_fw coef0255[] = {
+		WRITE_COEF(0x1b, 0x0c0b), /* LDO and MISC control */
+		WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
+		UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
+		WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */
+		WRITE_COEFEX(0x57, 0x03, 0x8aa6), /* Direct Drive HP Amp control */
+		{}
+	};
+	static struct coef_fw coef0233[] = {
+		WRITE_COEF(0x1b, 0x0c0b),
+		WRITE_COEF(0x45, 0xc429),
+		UPDATE_COEF(0x35, 0x4000, 0),
+		WRITE_COEF(0x06, 0x2104),
+		WRITE_COEF(0x1a, 0x0001),
+		WRITE_COEF(0x26, 0x0004),
+		WRITE_COEF(0x32, 0x42a3),
+		{}
+	};
+	static struct coef_fw coef0292[] = {
+		WRITE_COEF(0x76, 0x000e),
+		WRITE_COEF(0x6c, 0x2400),
+		WRITE_COEF(0x18, 0x7308),
+		WRITE_COEF(0x6b, 0xc429),
+		{}
+	};
+	static struct coef_fw coef0293[] = {
+		UPDATE_COEF(0x10, 7<<8, 6<<8), /* SET Line1 JD to 0 */
+		UPDATE_COEFEX(0x57, 0x05, 1<<15|1<<13, 0x0), /* SET charge pump by verb */
+		UPDATE_COEFEX(0x57, 0x03, 1<<10, 1<<10), /* SET EN_OSW to 1 */
+		UPDATE_COEF(0x1a, 1<<3, 1<<3), /* Combo JD gating with LINE1-VREFO */
+		WRITE_COEF(0x45, 0xc429), /* Set to TRS type */
+		UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
+		{}
+	};
+	static struct coef_fw coef0668[] = {
+		WRITE_COEF(0x15, 0x0d40),
+		WRITE_COEF(0xb7, 0x802b),
+		{}
+	};
 
 	switch (codec->vendor_id) {
 	case 0x10ec0255:
-		/* LDO and MISC control */
-		alc_write_coef_idx(codec, 0x1b, 0x0c0b);
-		/* UAJ function set to menual mode */
-		alc_write_coef_idx(codec, 0x45, 0xd089);
-		/* Direct Drive HP Amp control(Set to verb control)*/
-		val = alc_read_coefex_idx(codec, 0x57, 0x05);
-		alc_write_coefex_idx(codec, 0x57, 0x05, val & ~(1<<14));
-		/* Set MIC2 Vref gate with HP */
-		alc_write_coef_idx(codec, 0x06, 0x6104);
-		/* Direct Drive HP Amp control */
-		alc_write_coefex_idx(codec, 0x57, 0x03, 0x8aa6);
+		alc_process_coef_fw(codec, coef0255);
 		break;
 	case 0x10ec0233:
 	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);
+		alc_process_coef_fw(codec, coef0233);
 		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);
+		alc_process_coef_fw(codec, coef0292);
 		break;
 	case 0x10ec0293:
-		/* SET Line1 JD to 0 */
-		val = alc_read_coef_idx(codec, 0x10);
-		alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 6<<8);
-		/* SET charge pump by verb */
-		val = alc_read_coefex_idx(codec, 0x57, 0x05);
-		alc_write_coefex_idx(codec, 0x57, 0x05, (val & ~(1<<15|1<<13)) | 0x0);
-		/* SET EN_OSW to 1 */
-		val = alc_read_coefex_idx(codec, 0x57, 0x03);
-		alc_write_coefex_idx(codec, 0x57, 0x03, (val & ~(1<<10)) | (1<<10) );
-		/* Combo JD gating with LINE1-VREFO */
-		val = alc_read_coef_idx(codec, 0x1a);
-		alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | (1<<3));
-		/* Set to TRS type */
-		alc_write_coef_idx(codec, 0x45, 0xc429);
-		/* Combo Jack auto detect */
-		val = alc_read_coef_idx(codec, 0x4a);
-		alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x000e);
+		alc_process_coef_fw(codec, coef0293);
 		break;
 	case 0x10ec0668:
-		alc_write_coef_idx(codec, 0x15, 0x0d40);
-		alc_write_coef_idx(codec, 0xb7, 0x802b);
+		alc_process_coef_fw(codec, coef0668);
 		break;
 	}
 	codec_dbg(codec, "Headset jack set to unplugged mode.\n");
@@ -3686,55 +3432,65 @@
 static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
 				    hda_nid_t mic_pin)
 {
-	int val;
+	static struct coef_fw coef0255[] = {
+		WRITE_COEFEX(0x57, 0x03, 0x8aa6),
+		WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
+		{}
+	};
+	static struct coef_fw coef0233[] = {
+		UPDATE_COEF(0x35, 0, 1<<14),
+		WRITE_COEF(0x06, 0x2100),
+		WRITE_COEF(0x1a, 0x0021),
+		WRITE_COEF(0x26, 0x008c),
+		{}
+	};
+	static struct coef_fw coef0292[] = {
+		WRITE_COEF(0x19, 0xa208),
+		WRITE_COEF(0x2e, 0xacf0),
+		{}
+	};
+	static struct coef_fw coef0293[] = {
+		UPDATE_COEFEX(0x57, 0x05, 0, 1<<15|1<<13), /* SET charge pump by verb */
+		UPDATE_COEFEX(0x57, 0x03, 1<<10, 0), /* SET EN_OSW to 0 */
+		UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
+		{}
+	};
+	static struct coef_fw coef0688[] = {
+		WRITE_COEF(0xb7, 0x802b),
+		WRITE_COEF(0xb5, 0x1040),
+		UPDATE_COEF(0xc3, 0, 1<<12),
+		{}
+	};
 
 	switch (codec->vendor_id) {
 	case 0x10ec0255:
 		alc_write_coef_idx(codec, 0x45, 0xc489);
 		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-		alc_write_coefex_idx(codec, 0x57, 0x03, 0x8aa6);
-		/* Set MIC2 Vref gate to normal */
-		alc_write_coef_idx(codec, 0x06, 0x6100);
+		alc_process_coef_fw(codec, coef0255);
 		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
 		break;
 	case 0x10ec0233:
 	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);
+		alc_process_coef_fw(codec, coef0233);
 		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);
+		alc_process_coef_fw(codec, coef0292);
 		break;
 	case 0x10ec0293:
 		/* Set to TRS mode */
 		alc_write_coef_idx(codec, 0x45, 0xc429);
 		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-		/* SET charge pump by verb */
-		val = alc_read_coefex_idx(codec, 0x57, 0x05);
-		alc_write_coefex_idx(codec, 0x57, 0x05, (val & ~(1<<15|1<<13)) | (1<<15|1<<13));
-		/* SET EN_OSW to 0 */
-		val = alc_read_coefex_idx(codec, 0x57, 0x03);
-		alc_write_coefex_idx(codec, 0x57, 0x03, (val & ~(1<<10)) | 0x0);
-		/* Combo JD gating without LINE1-VREFO */
-		val = alc_read_coef_idx(codec, 0x1a);
-		alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | 0x0);
+		alc_process_coef_fw(codec, coef0293);
 		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
 		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);
+		alc_process_coef_fw(codec, coef0688);
 		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
 		break;
 	}
@@ -3743,40 +3499,54 @@
 
 static void alc_headset_mode_default(struct hda_codec *codec)
 {
-	int val;
+	static struct coef_fw coef0255[] = {
+		WRITE_COEF(0x45, 0xc089),
+		WRITE_COEF(0x45, 0xc489),
+		WRITE_COEFEX(0x57, 0x03, 0x8ea6),
+		WRITE_COEF(0x49, 0x0049),
+		{}
+	};
+	static struct coef_fw coef0233[] = {
+		WRITE_COEF(0x06, 0x2100),
+		WRITE_COEF(0x32, 0x4ea3),
+		{}
+	};
+	static struct coef_fw coef0292[] = {
+		WRITE_COEF(0x76, 0x000e),
+		WRITE_COEF(0x6c, 0x2400),
+		WRITE_COEF(0x6b, 0xc429),
+		WRITE_COEF(0x18, 0x7308),
+		{}
+	};
+	static struct coef_fw coef0293[] = {
+		UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
+		WRITE_COEF(0x45, 0xC429), /* Set to TRS type */
+		UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
+		{}
+	};
+	static struct coef_fw coef0688[] = {
+		WRITE_COEF(0x11, 0x0041),
+		WRITE_COEF(0x15, 0x0d40),
+		WRITE_COEF(0xb7, 0x802b),
+		{}
+	};
 
 	switch (codec->vendor_id) {
 	case 0x10ec0255:
-		alc_write_coef_idx(codec, 0x45, 0xc089);
-		alc_write_coef_idx(codec, 0x45, 0xc489);
-		alc_write_coefex_idx(codec, 0x57, 0x03, 0x8ea6);
-		alc_write_coef_idx(codec, 0x49, 0x0049);
+		alc_process_coef_fw(codec, coef0255);
 		break;
 	case 0x10ec0233:
 	case 0x10ec0283:
-		alc_write_coef_idx(codec, 0x06, 0x2100);
-		alc_write_coef_idx(codec, 0x32, 0x4ea3);
+		alc_process_coef_fw(codec, coef0233);
 		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);
+		alc_process_coef_fw(codec, coef0292);
 		break;
 	case 0x10ec0293:
-		/* Combo Jack auto detect */
-		val = alc_read_coef_idx(codec, 0x4a);
-		alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x000e);
-		/* Set to TRS type */
-		alc_write_coef_idx(codec, 0x45, 0xC429);
-		/* Combo JD gating without LINE1-VREFO */
-		val = alc_read_coef_idx(codec, 0x1a);
-		alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | 0x0);
+		alc_process_coef_fw(codec, coef0293);
 		break;
 	case 0x10ec0668:
-		alc_write_coef_idx(codec, 0x11, 0x0041);
-		alc_write_coef_idx(codec, 0x15, 0x0d40);
-		alc_write_coef_idx(codec, 0xb7, 0x802b);
+		alc_process_coef_fw(codec, coef0688);
 		break;
 	}
 	codec_dbg(codec, "Headset jack set to headphone (default) mode.\n");
@@ -3785,37 +3555,52 @@
 /* Iphone type */
 static void alc_headset_mode_ctia(struct hda_codec *codec)
 {
-	int val;
+	static struct coef_fw coef0255[] = {
+		WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
+		WRITE_COEF(0x1b, 0x0c2b),
+		WRITE_COEFEX(0x57, 0x03, 0x8ea6),
+		{}
+	};
+	static struct coef_fw coef0233[] = {
+		WRITE_COEF(0x45, 0xd429),
+		WRITE_COEF(0x1b, 0x0c2b),
+		WRITE_COEF(0x32, 0x4ea3),
+		{}
+	};
+	static struct coef_fw coef0292[] = {
+		WRITE_COEF(0x6b, 0xd429),
+		WRITE_COEF(0x76, 0x0008),
+		WRITE_COEF(0x18, 0x7388),
+		{}
+	};
+	static struct coef_fw coef0293[] = {
+		WRITE_COEF(0x45, 0xd429), /* Set to ctia type */
+		UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
+		{}
+	};
+	static struct coef_fw coef0688[] = {
+		WRITE_COEF(0x11, 0x0001),
+		WRITE_COEF(0x15, 0x0d60),
+		WRITE_COEF(0xc3, 0x0000),
+		{}
+	};
 
 	switch (codec->vendor_id) {
 	case 0x10ec0255:
-		/* Set to CTIA type */
-		alc_write_coef_idx(codec, 0x45, 0xd489);
-		alc_write_coef_idx(codec, 0x1b, 0x0c2b);
-		alc_write_coefex_idx(codec, 0x57, 0x03, 0x8ea6);
+		alc_process_coef_fw(codec, coef0255);
 		break;
 	case 0x10ec0233:
 	case 0x10ec0283:
-		alc_write_coef_idx(codec, 0x45, 0xd429);
-		alc_write_coef_idx(codec, 0x1b, 0x0c2b);
-		alc_write_coef_idx(codec, 0x32, 0x4ea3);
+		alc_process_coef_fw(codec, coef0233);
 		break;
 	case 0x10ec0292:
-		alc_write_coef_idx(codec, 0x6b, 0xd429);
-		alc_write_coef_idx(codec, 0x76, 0x0008);
-		alc_write_coef_idx(codec, 0x18, 0x7388);
+		alc_process_coef_fw(codec, coef0292);
 		break;
 	case 0x10ec0293:
-		/* Set to ctia type */
-		alc_write_coef_idx(codec, 0x45, 0xd429);
-		/* SET Line1 JD to 1 */
-		val = alc_read_coef_idx(codec, 0x10);
-		alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 7<<8);
+		alc_process_coef_fw(codec, coef0293);
 		break;
 	case 0x10ec0668:
-		alc_write_coef_idx(codec, 0x11, 0x0001);
-		alc_write_coef_idx(codec, 0x15, 0x0d60);
-		alc_write_coef_idx(codec, 0xc3, 0x0000);
+		alc_process_coef_fw(codec, coef0688);
 		break;
 	}
 	codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n");
@@ -3824,37 +3609,52 @@
 /* Nokia type */
 static void alc_headset_mode_omtp(struct hda_codec *codec)
 {
-	int val;
+	static struct coef_fw coef0255[] = {
+		WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */
+		WRITE_COEF(0x1b, 0x0c2b),
+		WRITE_COEFEX(0x57, 0x03, 0x8ea6),
+		{}
+	};
+	static struct coef_fw coef0233[] = {
+		WRITE_COEF(0x45, 0xe429),
+		WRITE_COEF(0x1b, 0x0c2b),
+		WRITE_COEF(0x32, 0x4ea3),
+		{}
+	};
+	static struct coef_fw coef0292[] = {
+		WRITE_COEF(0x6b, 0xe429),
+		WRITE_COEF(0x76, 0x0008),
+		WRITE_COEF(0x18, 0x7388),
+		{}
+	};
+	static struct coef_fw coef0293[] = {
+		WRITE_COEF(0x45, 0xe429), /* Set to omtp type */
+		UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
+		{}
+	};
+	static struct coef_fw coef0688[] = {
+		WRITE_COEF(0x11, 0x0001),
+		WRITE_COEF(0x15, 0x0d50),
+		WRITE_COEF(0xc3, 0x0000),
+		{}
+	};
 
 	switch (codec->vendor_id) {
 	case 0x10ec0255:
-		/* Set to OMTP Type */
-		alc_write_coef_idx(codec, 0x45, 0xe489);
-		alc_write_coef_idx(codec, 0x1b, 0x0c2b);
-		alc_write_coefex_idx(codec, 0x57, 0x03, 0x8ea6);
+		alc_process_coef_fw(codec, coef0255);
 		break;
 	case 0x10ec0233:
 	case 0x10ec0283:
-		alc_write_coef_idx(codec, 0x45, 0xe429);
-		alc_write_coef_idx(codec, 0x1b, 0x0c2b);
-		alc_write_coef_idx(codec, 0x32, 0x4ea3);
+		alc_process_coef_fw(codec, coef0233);
 		break;
 	case 0x10ec0292:
-		alc_write_coef_idx(codec, 0x6b, 0xe429);
-		alc_write_coef_idx(codec, 0x76, 0x0008);
-		alc_write_coef_idx(codec, 0x18, 0x7388);
+		alc_process_coef_fw(codec, coef0292);
 		break;
 	case 0x10ec0293:
-		/* Set to omtp type */
-		alc_write_coef_idx(codec, 0x45, 0xe429);
-		/* SET Line1 JD to 1 */
-		val = alc_read_coef_idx(codec, 0x10);
-		alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 7<<8);
+		alc_process_coef_fw(codec, coef0293);
 		break;
 	case 0x10ec0668:
-		alc_write_coef_idx(codec, 0x11, 0x0001);
-		alc_write_coef_idx(codec, 0x15, 0x0d50);
-		alc_write_coef_idx(codec, 0xc3, 0x0000);
+		alc_process_coef_fw(codec, coef0688);
 		break;
 	}
 	codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n");
@@ -3865,13 +3665,28 @@
 	int val;
 	bool is_ctia = false;
 	struct alc_spec *spec = codec->spec;
+	static struct coef_fw coef0255[] = {
+		WRITE_COEF(0x45, 0xd089), /* combo jack auto switch control(Check type)*/
+		WRITE_COEF(0x49, 0x0149), /* combo jack auto switch control(Vref
+ conteol) */
+		{}
+	};
+	static struct coef_fw coef0293[] = {
+		UPDATE_COEF(0x4a, 0x000f, 0x0008), /* Combo Jack auto detect */
+		WRITE_COEF(0x45, 0xD429), /* Set to ctia type */
+		{}
+	};
+	static struct coef_fw coef0688[] = {
+		WRITE_COEF(0x11, 0x0001),
+		WRITE_COEF(0xb7, 0x802b),
+		WRITE_COEF(0x15, 0x0d60),
+		WRITE_COEF(0xc3, 0x0c00),
+		{}
+	};
 
 	switch (codec->vendor_id) {
 	case 0x10ec0255:
-		/* combo jack auto switch control(Check type)*/
-		alc_write_coef_idx(codec, 0x45, 0xd089);
-		/* combo jack auto switch control(Vref conteol) */
-		alc_write_coef_idx(codec, 0x49, 0x0149);
+		alc_process_coef_fw(codec, coef0255);
 		msleep(300);
 		val = alc_read_coef_idx(codec, 0x46);
 		is_ctia = (val & 0x0070) == 0x0070;
@@ -3890,20 +3705,13 @@
 		is_ctia = (val & 0x001c) == 0x001c;
 		break;
 	case 0x10ec0293:
-		/* Combo Jack auto detect */
-		val = alc_read_coef_idx(codec, 0x4a);
-		alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x0008);
-		/* Set to ctia type */
-		alc_write_coef_idx(codec, 0x45, 0xD429);
+		alc_process_coef_fw(codec, coef0293);
 		msleep(300);
 		val = alc_read_coef_idx(codec, 0x46);
 		is_ctia = (val & 0x0070) == 0x0070;
 		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);
+		alc_process_coef_fw(codec, coef0688);
 		msleep(300);
 		val = alc_read_coef_idx(codec, 0xbe);
 		is_ctia = (val & 0x1c02) == 0x1c02;
@@ -3980,7 +3788,8 @@
 	alc_update_headset_mode(codec);
 }
 
-static void alc_update_headset_jack_cb(struct hda_codec *codec, struct hda_jack_tbl *jack)
+static void alc_update_headset_jack_cb(struct hda_codec *codec,
+				       struct hda_jack_callback *jack)
 {
 	struct alc_spec *spec = codec->spec;
 	spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN;
@@ -4039,11 +3848,15 @@
 static void alc255_set_default_jack_type(struct hda_codec *codec)
 {
 	/* Set to iphone type */
-	alc_write_coef_idx(codec, 0x1b, 0x880b);
-	alc_write_coef_idx(codec, 0x45, 0xd089);
-	alc_write_coef_idx(codec, 0x1b, 0x080b);
-	alc_write_coef_idx(codec, 0x46, 0x0004);
-	alc_write_coef_idx(codec, 0x1b, 0x0c0b);
+	static struct coef_fw fw[] = {
+		WRITE_COEF(0x1b, 0x880b),
+		WRITE_COEF(0x45, 0xd089),
+		WRITE_COEF(0x1b, 0x080b),
+		WRITE_COEF(0x46, 0x0004),
+		WRITE_COEF(0x1b, 0x0c0b),
+		{}
+	};
+	alc_process_coef_fw(codec, fw);
 	msleep(30);
 }
 
@@ -4138,10 +3951,8 @@
 				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);
+		alc_update_coef_idx(codec, 0xc2, ~0xfe, 0);
 		snd_hda_set_pin_ctl_cache(codec, 0x18, 0);
 	}
 	alc_fixup_headset_mode(codec, fix, action);
@@ -4218,7 +4029,7 @@
 }
 
 static void alc283_hp_automute_hook(struct hda_codec *codec,
-				    struct hda_jack_tbl *jack)
+				    struct hda_jack_callback *jack)
 {
 	struct alc_spec *spec = codec->spec;
 	int vref;
@@ -4237,7 +4048,6 @@
 				    const struct hda_fixup *fix, int action)
 {
 	struct alc_spec *spec = codec->spec;
-	int val;
 
 	switch (action) {
 	case HDA_FIXUP_ACT_PRE_PROBE:
@@ -4248,11 +4058,9 @@
 	case HDA_FIXUP_ACT_INIT:
 		/* MIC2-VREF control */
 		/* Set to manual mode */
-		val = alc_read_coef_idx(codec, 0x06);
-		alc_write_coef_idx(codec, 0x06, val & ~0x000c);
+		alc_update_coef_idx(codec, 0x06, 0x000c, 0);
 		/* Enable Line1 input control by verb */
-		val = alc_read_coef_idx(codec, 0x1a);
-		alc_write_coef_idx(codec, 0x1a, val | (1 << 4));
+		alc_update_coef_idx(codec, 0x1a, 0, 1 << 4);
 		break;
 	}
 }
@@ -4261,7 +4069,6 @@
 				    const struct hda_fixup *fix, int action)
 {
 	struct alc_spec *spec = codec->spec;
-	int val;
 
 	switch (action) {
 	case HDA_FIXUP_ACT_PRE_PROBE:
@@ -4270,8 +4077,7 @@
 	case HDA_FIXUP_ACT_INIT:
 		/* MIC2-VREF control */
 		/* Set to manual mode */
-		val = alc_read_coef_idx(codec, 0x06);
-		alc_write_coef_idx(codec, 0x06, val & ~0x000c);
+		alc_update_coef_idx(codec, 0x06, 0x000c, 0);
 		break;
 	}
 }
@@ -4309,7 +4115,6 @@
 		spec->gen.auto_mute_via_amp = 1;
 		spec->gen.automute_hook = asus_tx300_automute;
 		snd_hda_jack_detect_enable_callback(codec, 0x1b,
-						    HDA_GEN_HP_EVENT,
 						    snd_hda_gen_hp_automute);
 		break;
 	case HDA_FIXUP_ACT_BUILD:
@@ -4576,7 +4381,7 @@
 	},
 	[ALC269_FIXUP_INV_DMIC] = {
 		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_inv_dmic_0x12,
+		.v.func = alc_fixup_inv_dmic,
 	},
 	[ALC269_FIXUP_NO_SHUTUP] = {
 		.type = HDA_FIXUP_FUNC,
@@ -4887,122 +4692,45 @@
 	SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572),
 	SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS),
 	SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
-	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, 0x05cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
-	SND_PCI_QUIRK(0x1028, 0x05cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
 	SND_PCI_QUIRK(0x1028, 0x05da, "Dell Vostro 5460", ALC290_FIXUP_SUBWOOFER),
-	SND_PCI_QUIRK(0x1028, 0x05de, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
-	SND_PCI_QUIRK(0x1028, 0x05e0, "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(0x1028, 0x05f8, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-	SND_PCI_QUIRK(0x1028, 0x05f9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-	SND_PCI_QUIRK(0x1028, 0x05fb, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-	SND_PCI_QUIRK(0x1028, 0x0606, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-	SND_PCI_QUIRK(0x1028, 0x0608, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-	SND_PCI_QUIRK(0x1028, 0x0609, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
 	SND_PCI_QUIRK(0x1028, 0x0610, "Dell", ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED),
-	SND_PCI_QUIRK(0x1028, 0x0613, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-	SND_PCI_QUIRK(0x1028, 0x0614, "Dell Inspiron 3135", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
 	SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
 	SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
 	SND_PCI_QUIRK(0x1028, 0x061f, "Dell", ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED),
 	SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK),
-	SND_PCI_QUIRK(0x1028, 0x063f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
 	SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
 	SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
-	SND_PCI_QUIRK(0x1028, 0x0668, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE),
-	SND_PCI_QUIRK(0x1028, 0x0669, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE),
-	SND_PCI_QUIRK(0x1028, 0x0684, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
-	SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
-	SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
 	SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
 	SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_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(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED),
 	/* ALC282 */
-	SND_PCI_QUIRK(0x103c, 0x21f8, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x21f9, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x220d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x220e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x220f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x2210, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x2211, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x2212, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x2213, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x2234, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-	SND_PCI_QUIRK(0x103c, 0x2235, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
 	SND_PCI_QUIRK(0x103c, 0x2236, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
 	SND_PCI_QUIRK(0x103c, 0x2237, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
 	SND_PCI_QUIRK(0x103c, 0x2238, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
 	SND_PCI_QUIRK(0x103c, 0x2239, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-	SND_PCI_QUIRK(0x103c, 0x2246, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-	SND_PCI_QUIRK(0x103c, 0x2247, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-	SND_PCI_QUIRK(0x103c, 0x2248, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-	SND_PCI_QUIRK(0x103c, 0x2249, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-	SND_PCI_QUIRK(0x103c, 0x224a, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
 	SND_PCI_QUIRK(0x103c, 0x224b, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-	SND_PCI_QUIRK(0x103c, 0x224c, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-	SND_PCI_QUIRK(0x103c, 0x224d, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-	SND_PCI_QUIRK(0x103c, 0x2266, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x2267, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x2268, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x2269, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x226a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x226c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x226d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x226e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x226f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x227a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x227b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x22a0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x22bf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x22c0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x22c1, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x22c2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x22cd, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x22ce, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x22d0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x22da, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-	SND_PCI_QUIRK(0x103c, 0x22db, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
 	SND_PCI_QUIRK(0x103c, 0x22dc, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
 	SND_PCI_QUIRK(0x103c, 0x22fb, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
 	SND_PCI_QUIRK(0x103c, 0x8004, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
 	/* ALC290 */
 	SND_PCI_QUIRK(0x103c, 0x221b, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-	SND_PCI_QUIRK(0x103c, 0x221c, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-	SND_PCI_QUIRK(0x103c, 0x221d, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-	SND_PCI_QUIRK(0x103c, 0x2220, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
 	SND_PCI_QUIRK(0x103c, 0x2221, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-	SND_PCI_QUIRK(0x103c, 0x2222, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-	SND_PCI_QUIRK(0x103c, 0x2223, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-	SND_PCI_QUIRK(0x103c, 0x2224, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
 	SND_PCI_QUIRK(0x103c, 0x2225, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
 	SND_PCI_QUIRK(0x103c, 0x2246, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
 	SND_PCI_QUIRK(0x103c, 0x2247, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
@@ -5017,8 +4745,6 @@
 	SND_PCI_QUIRK(0x103c, 0x2259, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
 	SND_PCI_QUIRK(0x103c, 0x225a, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
 	SND_PCI_QUIRK(0x103c, 0x2260, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x2261, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x2262, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x2263, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x2264, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x2265, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
@@ -5026,23 +4752,13 @@
 	SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
 	SND_PCI_QUIRK(0x103c, 0x2277, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
 	SND_PCI_QUIRK(0x103c, 0x2278, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-	SND_PCI_QUIRK(0x103c, 0x227d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x227e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x227f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x2280, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x2281, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x2282, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x2289, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x228a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x228b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x228c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x228d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x228e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x22c5, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x22c6, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x22c7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x22c8, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-	SND_PCI_QUIRK(0x103c, 0x22c3, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x22c4, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x2334, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x2335, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
@@ -5070,6 +4786,7 @@
 	SND_PCI_QUIRK(0x104d, 0x9099, "Sony VAIO S13", ALC275_FIXUP_SONY_DISABLE_AAMIX),
 	SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK),
 	SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC),
+	SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
 	SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_BXBT2807_MIC),
 	SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
 	SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
@@ -5085,12 +4802,13 @@
 	SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad T440s", ALC292_FIXUP_TPT440_DOCK),
 	SND_PCI_QUIRK(0x17aa, 0x220e, "Thinkpad T440p", ALC292_FIXUP_TPT440_DOCK),
 	SND_PCI_QUIRK(0x17aa, 0x2210, "Thinkpad T540p", ALC292_FIXUP_TPT440_DOCK),
-	SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+	SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad T440", ALC292_FIXUP_TPT440_DOCK),
 	SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
 	SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
 	SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
 	SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
 	SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
+	SND_PCI_QUIRK(0x17aa, 0x501e, "Thinkpad L440", ALC292_FIXUP_TPT440_DOCK),
 	SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
 	SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
 	SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
@@ -5173,28 +4891,58 @@
 	{}
 };
 
+#define ALC255_STANDARD_PINS \
+	{0x18, 0x411111f0}, \
+	{0x19, 0x411111f0}, \
+	{0x1a, 0x411111f0}, \
+	{0x1b, 0x411111f0}, \
+	{0x1e, 0x411111f0}
+
+#define ALC282_STANDARD_PINS \
+	{0x14, 0x90170110}, \
+	{0x18, 0x411111f0}, \
+	{0x1a, 0x411111f0}, \
+	{0x1b, 0x411111f0}, \
+	{0x1e, 0x411111f0}
+
+#define ALC290_STANDARD_PINS \
+	{0x12, 0x99a30130}, \
+	{0x13, 0x40000000}, \
+	{0x16, 0x411111f0}, \
+	{0x17, 0x411111f0}, \
+	{0x19, 0x411111f0}, \
+	{0x1b, 0x411111f0}, \
+	{0x1e, 0x411111f0}
+
+#define ALC292_STANDARD_PINS \
+	{0x14, 0x90170110}, \
+	{0x15, 0x0221401f}, \
+	{0x1a, 0x411111f0}, \
+	{0x1b, 0x411111f0}, \
+	{0x1d, 0x40700001}, \
+	{0x1e, 0x411111f0}
+
 static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
+	SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE,
+		ALC255_STANDARD_PINS,
+		{0x12, 0x40300000},
+		{0x14, 0x90170110},
+		{0x17, 0x411111f0},
+		{0x1d, 0x40538029},
+		{0x21, 0x02211020}),
 	SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+		ALC255_STANDARD_PINS,
 		{0x12, 0x90a60140},
 		{0x14, 0x90170110},
 		{0x17, 0x40000000},
-		{0x18, 0x411111f0},
-		{0x19, 0x411111f0},
-		{0x1a, 0x411111f0},
-		{0x1b, 0x411111f0},
 		{0x1d, 0x40700001},
-		{0x1e, 0x411111f0},
 		{0x21, 0x02211020}),
 	SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+		ALC255_STANDARD_PINS,
 		{0x12, 0x90a60160},
 		{0x14, 0x90170120},
 		{0x17, 0x40000000},
-		{0x18, 0x411111f0},
-		{0x19, 0x411111f0},
-		{0x1a, 0x411111f0},
-		{0x1b, 0x411111f0},
 		{0x1d, 0x40700001},
-		{0x1e, 0x411111f0},
 		{0x21, 0x02211030}),
 	SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
 		{0x12, 0x90a60160},
@@ -5208,70 +4956,101 @@
 		{0x1e, 0x411111f0},
 		{0x21, 0x0321102f}),
 	SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+		ALC255_STANDARD_PINS,
 		{0x12, 0x90a60160},
 		{0x14, 0x90170130},
 		{0x17, 0x40000000},
-		{0x18, 0x411111f0},
-		{0x19, 0x411111f0},
-		{0x1a, 0x411111f0},
-		{0x1b, 0x411111f0},
 		{0x1d, 0x40700001},
-		{0x1e, 0x411111f0},
 		{0x21, 0x02211040}),
 	SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+		ALC255_STANDARD_PINS,
 		{0x12, 0x90a60160},
 		{0x14, 0x90170140},
 		{0x17, 0x40000000},
-		{0x18, 0x411111f0},
-		{0x19, 0x411111f0},
-		{0x1a, 0x411111f0},
-		{0x1b, 0x411111f0},
 		{0x1d, 0x40700001},
-		{0x1e, 0x411111f0},
 		{0x21, 0x02211050}),
 	SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+		ALC255_STANDARD_PINS,
 		{0x12, 0x90a60170},
 		{0x14, 0x90170120},
 		{0x17, 0x40000000},
-		{0x18, 0x411111f0},
-		{0x19, 0x411111f0},
-		{0x1a, 0x411111f0},
-		{0x1b, 0x411111f0},
 		{0x1d, 0x40700001},
-		{0x1e, 0x411111f0},
 		{0x21, 0x02211030}),
 	SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+		ALC255_STANDARD_PINS,
 		{0x12, 0x90a60170},
 		{0x14, 0x90170130},
 		{0x17, 0x40000000},
-		{0x18, 0x411111f0},
-		{0x19, 0x411111f0},
-		{0x1a, 0x411111f0},
-		{0x1b, 0x411111f0},
 		{0x1d, 0x40700001},
-		{0x1e, 0x411111f0},
 		{0x21, 0x02211040}),
-	SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP 15 Touchsmart", ALC269_FIXUP_HP_MUTE_LED_MIC1,
-		{0x12, 0x99a30130},
+	SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED,
+		{0x12, 0x90a60140},
+		{0x13, 0x40000000},
 		{0x14, 0x90170110},
-		{0x17, 0x40000000},
-		{0x18, 0x411111f0},
-		{0x19, 0x03a11020},
-		{0x1a, 0x411111f0},
-		{0x1b, 0x411111f0},
-		{0x1d, 0x40f41905},
-		{0x1e, 0x411111f0},
-		{0x21, 0x0321101f}),
-	SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
-		{0x12, 0x90a60130},
-		{0x14, 0x90170110},
-		{0x17, 0x40020008},
-		{0x18, 0x411111f0},
+		{0x15, 0x0421101f},
+		{0x16, 0x411111f0},
+		{0x17, 0x411111f0},
+		{0x18, 0x02811030},
 		{0x19, 0x411111f0},
-		{0x1a, 0x411111f0},
-		{0x1b, 0x411111f0},
+		{0x1a, 0x04a1103f},
+		{0x1b, 0x02011020},
+		{0x1d, 0x40700001},
+		{0x1e, 0x411111f0}),
+	SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP 15 Touchsmart", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+		ALC282_STANDARD_PINS,
+		{0x12, 0x99a30130},
+		{0x17, 0x40000000},
+		{0x19, 0x03a11020},
+		{0x1d, 0x40f41905},
+		{0x21, 0x0321101f}),
+	SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+		ALC282_STANDARD_PINS,
+		{0x12, 0x99a30130},
+		{0x17, 0x40020008},
+		{0x19, 0x03a11020},
 		{0x1d, 0x40e00001},
-		{0x1e, 0x411111f0},
+		{0x21, 0x03211040}),
+	SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+		ALC282_STANDARD_PINS,
+		{0x12, 0x99a30130},
+		{0x17, 0x40000000},
+		{0x19, 0x03a11030},
+		{0x1d, 0x40e00001},
+		{0x21, 0x03211020}),
+	SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+		ALC282_STANDARD_PINS,
+		{0x12, 0x99a30130},
+		{0x17, 0x40000000},
+		{0x19, 0x03a11030},
+		{0x1d, 0x40f00001},
+		{0x21, 0x03211020}),
+	SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+		ALC282_STANDARD_PINS,
+		{0x12, 0x99a30130},
+		{0x17, 0x40000000},
+		{0x19, 0x04a11020},
+		{0x1d, 0x40f00001},
+		{0x21, 0x0421101f}),
+	SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+		ALC282_STANDARD_PINS,
+		{0x12, 0x99a30130},
+		{0x17, 0x40000000},
+		{0x19, 0x03a11030},
+		{0x1d, 0x40f00001},
+		{0x21, 0x04211020}),
+	SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED,
+		ALC282_STANDARD_PINS,
+		{0x12, 0x90a60140},
+		{0x17, 0x40000000},
+		{0x19, 0x04a11030},
+		{0x1d, 0x40f00001},
+		{0x21, 0x04211020}),
+	SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+		ALC282_STANDARD_PINS,
+		{0x12, 0x90a60130},
+		{0x17, 0x40020008},
+		{0x19, 0x411111f0},
+		{0x1d, 0x40e00001},
 		{0x21, 0x0321101f}),
 	SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
 		{0x12, 0x90a60160},
@@ -5284,42 +5063,97 @@
 		{0x1d, 0x40700001},
 		{0x1e, 0x411111f0},
 		{0x21, 0x02211030}),
-	SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL3_MIC_NO_PRESENCE,
+	SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+		ALC282_STANDARD_PINS,
+		{0x12, 0x90a60130},
+		{0x17, 0x40020008},
+		{0x19, 0x03a11020},
+		{0x1d, 0x40e00001},
+		{0x21, 0x0321101f}),
+	SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+		ALC290_STANDARD_PINS,
+		{0x14, 0x411111f0},
+		{0x15, 0x04211040},
+		{0x18, 0x90170112},
+		{0x1a, 0x04a11020},
+		{0x1d, 0x4075812d}),
+	SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+		ALC290_STANDARD_PINS,
+		{0x14, 0x411111f0},
+		{0x15, 0x04211040},
+		{0x18, 0x90170110},
+		{0x1a, 0x04a11020},
+		{0x1d, 0x4075812d}),
+	SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+		ALC290_STANDARD_PINS,
+		{0x14, 0x411111f0},
+		{0x15, 0x0421101f},
+		{0x18, 0x411111f0},
+		{0x1a, 0x04a11020},
+		{0x1d, 0x4075812d}),
+	SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+		ALC290_STANDARD_PINS,
+		{0x14, 0x411111f0},
+		{0x15, 0x04211020},
+		{0x18, 0x411111f0},
+		{0x1a, 0x04a11040},
+		{0x1d, 0x4076a12d}),
+	SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+		ALC290_STANDARD_PINS,
+		{0x14, 0x90170110},
+		{0x15, 0x04211020},
+		{0x18, 0x411111f0},
+		{0x1a, 0x04a11040},
+		{0x1d, 0x4076a12d}),
+	SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+		ALC290_STANDARD_PINS,
+		{0x14, 0x90170110},
+		{0x15, 0x04211020},
+		{0x18, 0x411111f0},
+		{0x1a, 0x04a11020},
+		{0x1d, 0x4076a12d}),
+	SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+		ALC290_STANDARD_PINS,
+		{0x14, 0x90170110},
+		{0x15, 0x0421101f},
+		{0x18, 0x411111f0},
+		{0x1a, 0x04a11020},
+		{0x1d, 0x4075812d}),
+	SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE,
+		ALC292_STANDARD_PINS,
 		{0x12, 0x90a60140},
 		{0x13, 0x411111f0},
-		{0x14, 0x90170110},
-		{0x15, 0x0221401f},
+		{0x16, 0x01014020},
+		{0x18, 0x411111f0},
+		{0x19, 0x01a19030}),
+	SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE,
+		ALC292_STANDARD_PINS,
+		{0x12, 0x90a60140},
+		{0x13, 0x411111f0},
+		{0x16, 0x01014020},
+		{0x18, 0x02a19031},
+		{0x19, 0x01a1903e}),
+	SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL3_MIC_NO_PRESENCE,
+		ALC292_STANDARD_PINS,
+		{0x12, 0x90a60140},
+		{0x13, 0x411111f0},
 		{0x16, 0x411111f0},
 		{0x18, 0x411111f0},
-		{0x19, 0x411111f0},
-		{0x1a, 0x411111f0},
-		{0x1b, 0x411111f0},
-		{0x1d, 0x40700001},
-		{0x1e, 0x411111f0}),
+		{0x19, 0x411111f0}),
 	SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
+		ALC292_STANDARD_PINS,
 		{0x12, 0x40000000},
 		{0x13, 0x90a60140},
-		{0x14, 0x90170110},
-		{0x15, 0x0221401f},
 		{0x16, 0x21014020},
 		{0x18, 0x411111f0},
-		{0x19, 0x21a19030},
-		{0x1a, 0x411111f0},
-		{0x1b, 0x411111f0},
-		{0x1d, 0x40700001},
-		{0x1e, 0x411111f0}),
+		{0x19, 0x21a19030}),
 	SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
+		ALC292_STANDARD_PINS,
 		{0x12, 0x40000000},
 		{0x13, 0x90a60140},
-		{0x14, 0x90170110},
-		{0x15, 0x0221401f},
 		{0x16, 0x411111f0},
 		{0x18, 0x411111f0},
-		{0x19, 0x411111f0},
-		{0x1a, 0x411111f0},
-		{0x1b, 0x411111f0},
-		{0x1d, 0x40700001},
-		{0x1e, 0x411111f0}),
+		{0x19, 0x411111f0}),
 	{}
 };
 
@@ -5342,10 +5176,8 @@
 	}
 
 	if ((alc_get_coef0(codec) & 0x00ff) == 0x017) {
-		val = alc_read_coef_idx(codec, 0x04);
 		/* Power up output pin */
-		if (val != -1)
-			alc_write_coef_idx(codec, 0x04, val | (1<<11));
+		alc_update_coef_idx(codec, 0x04, 0, 1<<11);
 	}
 
 	if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
@@ -5361,13 +5193,11 @@
 		}
 	}
 
-	val = alc_read_coef_idx(codec, 0xd); /* Class D */
-	if (val != -1)
-		alc_write_coef_idx(codec, 0xd, val | (1<<14));
+	/* Class D */
+	alc_update_coef_idx(codec, 0xd, 0, 1<<14);
 
-	val = alc_read_coef_idx(codec, 0x4); /* HP */
-	if (val != -1)
-		alc_write_coef_idx(codec, 0x4, val | (1<<11));
+	/* HP */
+	alc_update_coef_idx(codec, 0x4, 0, 1<<11);
 }
 
 /*
@@ -6012,7 +5842,7 @@
 	},
 	[ALC662_FIXUP_INV_DMIC] = {
 		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_inv_dmic_0x12,
+		.v.func = alc_fixup_inv_dmic,
 	},
 	[ALC668_FIXUP_DELL_XPS13] = {
 		.type = HDA_FIXUP_FUNC,
@@ -6247,16 +6077,14 @@
 
 static void alc662_fill_coef(struct hda_codec *codec)
 {
-	int val, coef;
+	int coef;
 
 	coef = alc_get_coef0(codec);
 
 	switch (codec->vendor_id) {
 	case 0x10ec0662:
-		if ((coef & 0x00f0) == 0x0030) {
-			val = alc_read_coef_idx(codec, 0x4); /* EAPD Ctrl */
-			alc_write_coef_idx(codec, 0x4, val & ~(1<<10));
-		}
+		if ((coef & 0x00f0) == 0x0030)
+			alc_update_coef_idx(codec, 0x4, 1<<10, 0); /* EAPD Ctrl */
 		break;
 	case 0x10ec0272:
 	case 0x10ec0273:
@@ -6265,8 +6093,7 @@
 	case 0x10ec0670:
 	case 0x10ec0671:
 	case 0x10ec0672:
-		val = alc_read_coef_idx(codec, 0xd); /* EAPD Ctrl */
-		alc_write_coef_idx(codec, 0xd, val | (1<<14));
+		alc_update_coef_idx(codec, 0xd, 0, 1<<14); /* EAPD Ctrl */
 		break;
 	}
 }
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 98cd190..4f6413e 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -32,7 +32,6 @@
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/jack.h>
-#include <sound/tlv.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_auto_parser.h"
@@ -41,11 +40,6 @@
 #include "hda_generic.h"
 
 enum {
-	STAC_VREF_EVENT	= 8,
-	STAC_PWR_EVENT,
-};
-
-enum {
 	STAC_REF,
 	STAC_9200_OQO,
 	STAC_9200_DELL_D21,
@@ -487,7 +481,7 @@
 
 /* update power bit per jack plug/unplug */
 static void jack_update_power(struct hda_codec *codec,
-			      struct hda_jack_tbl *jack)
+			      struct hda_jack_callback *jack)
 {
 	struct sigmatel_spec *spec = codec->spec;
 	int i;
@@ -495,9 +489,9 @@
 	if (!spec->num_pwrs)
 		return;
 
-	if (jack && jack->nid) {
-		stac_toggle_power_map(codec, jack->nid,
-				      snd_hda_jack_detect(codec, jack->nid),
+	if (jack && jack->tbl->nid) {
+		stac_toggle_power_map(codec, jack->tbl->nid,
+				      snd_hda_jack_detect(codec, jack->tbl->nid),
 				      true);
 		return;
 	}
@@ -505,42 +499,19 @@
 	/* update all jacks */
 	for (i = 0; i < spec->num_pwrs; i++) {
 		hda_nid_t nid = spec->pwr_nids[i];
-		jack = snd_hda_jack_tbl_get(codec, nid);
-		if (!jack || !jack->action)
+		if (!snd_hda_jack_tbl_get(codec, nid))
 			continue;
-		if (jack->action == STAC_PWR_EVENT ||
-		    jack->action <= HDA_GEN_LAST_EVENT)
-			stac_toggle_power_map(codec, nid,
-					      snd_hda_jack_detect(codec, nid),
-					      false);
+		stac_toggle_power_map(codec, nid,
+				      snd_hda_jack_detect(codec, nid),
+				      false);
 	}
 
 	snd_hda_codec_write(codec, codec->afg, 0, AC_VERB_IDT_SET_POWER_MAP,
 			    spec->power_map_bits);
 }
 
-static void stac_hp_automute(struct hda_codec *codec,
-				 struct hda_jack_tbl *jack)
-{
-	snd_hda_gen_hp_automute(codec, jack);
-	jack_update_power(codec, jack);
-}
-
-static void stac_line_automute(struct hda_codec *codec,
-				   struct hda_jack_tbl *jack)
-{
-	snd_hda_gen_line_automute(codec, jack);
-	jack_update_power(codec, jack);
-}
-
-static void stac_mic_autoswitch(struct hda_codec *codec,
-				struct hda_jack_tbl *jack)
-{
-	snd_hda_gen_mic_autoswitch(codec, jack);
-	jack_update_power(codec, jack);
-}
-
-static void stac_vref_event(struct hda_codec *codec, struct hda_jack_tbl *event)
+static void stac_vref_event(struct hda_codec *codec,
+			    struct hda_jack_callback *event)
 {
 	unsigned int data;
 
@@ -563,13 +534,10 @@
 		hda_nid_t nid = spec->pwr_nids[i];
 		unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
 		def_conf = get_defcfg_connect(def_conf);
-		if (snd_hda_jack_tbl_get(codec, nid))
-			continue;
 		if (def_conf == AC_JACK_PORT_COMPLEX &&
 		    spec->vref_mute_led_nid != nid &&
 		    is_jack_detectable(codec, nid)) {
 			snd_hda_jack_detect_enable_callback(codec, nid,
-							    STAC_PWR_EVENT,
 							    jack_update_power);
 		} else {
 			if (def_conf == AC_JACK_PORT_NONE)
@@ -3020,7 +2988,7 @@
 				      const struct hda_fixup *fix, int action)
 {
 	struct sigmatel_spec *spec = codec->spec;
-	struct hda_jack_tbl *jack;
+	struct hda_jack_callback *jack;
 
 	if (action != HDA_FIXUP_ACT_PRE_PROBE)
 		return;
@@ -3028,11 +2996,9 @@
 	/* Enable VREF power saving on GPIO1 detect */
 	snd_hda_codec_write_cache(codec, codec->afg, 0,
 				  AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
-	snd_hda_jack_detect_enable_callback(codec, codec->afg,
-					    STAC_VREF_EVENT,
-					    stac_vref_event);
-	jack = snd_hda_jack_tbl_get(codec, codec->afg);
-	if (jack)
+	jack = snd_hda_jack_detect_enable_callback(codec, codec->afg,
+						   stac_vref_event);
+	if (!IS_ERR(jack))
 		jack->private_data = 0x02;
 
 	spec->gpio_mask |= 0x02;
@@ -4044,7 +4010,7 @@
 				    const struct hda_fixup *fix, int action)
 {
 	struct sigmatel_spec *spec = codec->spec;
-	struct hda_jack_tbl *jack;
+	struct hda_jack_callback *jack;
 
 	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
 		snd_hda_apply_pincfgs(codec, dell_9205_m43_pin_configs);
@@ -4052,11 +4018,9 @@
 		/* Enable unsol response for GPIO4/Dock HP connection */
 		snd_hda_codec_write_cache(codec, codec->afg, 0,
 			AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
-		snd_hda_jack_detect_enable_callback(codec, codec->afg,
-						    STAC_VREF_EVENT,
-						    stac_vref_event);
-		jack = snd_hda_jack_tbl_get(codec, codec->afg);
-		if (jack)
+		jack = snd_hda_jack_detect_enable_callback(codec, codec->afg,
+							   stac_vref_event);
+		if (!IS_ERR(jack))
 			jack->private_data = 0x01;
 
 		spec->gpio_dir = 0x0b;
@@ -4219,17 +4183,11 @@
 	spec->gen.pcm_capture_hook = stac_capture_pcm_hook;
 
 	spec->gen.automute_hook = stac_update_outputs;
-	spec->gen.hp_automute_hook = stac_hp_automute;
-	spec->gen.line_automute_hook = stac_line_automute;
-	spec->gen.mic_autoswitch_hook = stac_mic_autoswitch;
 
 	err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
 	if (err < 0)
 		return err;
 
-	/* minimum value is actually mute */
-	spec->gen.vmaster_tlv[3] |= TLV_DB_SCALE_MUTE;
-
 	/* setup analog beep controls */
 	if (spec->anabeep_nid > 0) {
 		err = stac_auto_create_beep_ctls(codec,
@@ -4276,16 +4234,8 @@
 			return err;
 	}
 
-	return 0;
-}
-
-static int stac_build_controls(struct hda_codec *codec)
-{
-	int err = snd_hda_gen_build_controls(codec);
-
-	if (err < 0)
-		return err;
 	stac_init_power_map(codec);
+
 	return 0;
 }
 
@@ -4399,7 +4349,7 @@
 #endif /* CONFIG_PM */
 
 static const struct hda_codec_ops stac_patch_ops = {
-	.build_controls = stac_build_controls,
+	.build_controls = snd_hda_gen_build_controls,
 	.build_pcms = snd_hda_gen_build_pcms,
 	.init = stac_init,
 	.free = stac_free,
@@ -4420,6 +4370,7 @@
 	snd_hda_gen_spec_init(&spec->gen);
 	codec->spec = spec;
 	codec->no_trigger_sense = 1; /* seems common with STAC/IDT codecs */
+	spec->gen.dac_min_mute = true;
 	return 0;
 }
 
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 7781662..6c206b6 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -118,7 +118,6 @@
 				  struct hda_codec *codec,
 				  struct snd_pcm_substream *substream,
 				  int action);
-static void via_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *tbl);
 
 static struct via_spec *via_new_spec(struct hda_codec *codec)
 {
@@ -575,25 +574,12 @@
 	{} /* terminator */
 };
 
-static void via_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *tbl)
-{
-	set_widgets_power_state(codec);
-	snd_hda_gen_hp_automute(codec, tbl);
-}
-
-static void via_line_automute(struct hda_codec *codec, struct hda_jack_tbl *tbl)
-{
-	set_widgets_power_state(codec);
-	snd_hda_gen_line_automute(codec, tbl);
-}
-
-static void via_jack_powerstate_event(struct hda_codec *codec, struct hda_jack_tbl *tbl)
+static void via_jack_powerstate_event(struct hda_codec *codec,
+				      struct hda_jack_callback *tbl)
 {
 	set_widgets_power_state(codec);
 }
 
-#define VIA_JACK_EVENT	(HDA_GEN_LAST_EVENT + 1)
-
 static void via_set_jack_unsol_events(struct hda_codec *codec)
 {
 	struct via_spec *spec = codec->spec;
@@ -601,25 +587,17 @@
 	hda_nid_t pin;
 	int i;
 
-	spec->gen.hp_automute_hook = via_hp_automute;
-	if (cfg->speaker_pins[0])
-		spec->gen.line_automute_hook = via_line_automute;
-
 	for (i = 0; i < cfg->line_outs; i++) {
 		pin = cfg->line_out_pins[i];
-		if (pin && !snd_hda_jack_tbl_get(codec, pin) &&
-		    is_jack_detectable(codec, pin))
+		if (pin && is_jack_detectable(codec, pin))
 			snd_hda_jack_detect_enable_callback(codec, pin,
-							    VIA_JACK_EVENT,
 							    via_jack_powerstate_event);
 	}
 
 	for (i = 0; i < cfg->num_inputs; i++) {
 		pin = cfg->line_out_pins[i];
-		if (pin && !snd_hda_jack_tbl_get(codec, pin) &&
-		    is_jack_detectable(codec, pin))
+		if (pin && is_jack_detectable(codec, pin))
 			snd_hda_jack_detect_enable_callback(codec, pin,
-							    VIA_JACK_EVENT,
 							    via_jack_powerstate_event);
 	}
 }
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index 87f7fc4..206ed2c 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -2528,7 +2528,7 @@
 	if (!ice->port)
 		goto __hw_end;
 	/* mask all interrupts */
-	outb(0xc0, ICEMT(ice, IRQ));
+	outb(ICE1712_MULTI_CAPTURE | ICE1712_MULTI_PLAYBACK, ICEMT(ice, IRQ));
 	outb(0xff, ICEREG(ice, IRQMASK));
 	/* --- */
 __hw_end:
diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c
index a671f08..601315a 100644
--- a/sound/pci/lx6464es/lx6464es.c
+++ b/sound/pci/lx6464es/lx6464es.c
@@ -279,7 +279,6 @@
 {
 	struct lx6464es *chip = snd_pcm_substream_chip(substream);
 	snd_pcm_uframes_t pos;
-	unsigned long flags;
 	int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
 
 	struct lx_stream *lx_stream = is_capture ? &chip->capture_stream :
@@ -287,9 +286,9 @@
 
 	dev_dbg(chip->card->dev, "->lx_pcm_stream_pointer\n");
 
-	spin_lock_irqsave(&chip->lock, flags);
+	mutex_lock(&chip->lock);
 	pos = lx_stream->frame_pos * substream->runtime->period_size;
-	spin_unlock_irqrestore(&chip->lock, flags);
+	mutex_unlock(&chip->lock);
 
 	dev_dbg(chip->card->dev, "stream_pointer at %ld\n", pos);
 	return pos;
@@ -485,8 +484,8 @@
 
 }
 
-static void lx_trigger_tasklet_dispatch_stream(struct lx6464es *chip,
-					       struct lx_stream *lx_stream)
+static void lx_trigger_dispatch_stream(struct lx6464es *chip,
+				       struct lx_stream *lx_stream)
 {
 	switch (lx_stream->status) {
 	case LX_STREAM_STATUS_SCHEDULE_RUN:
@@ -502,24 +501,12 @@
 	}
 }
 
-static void lx_trigger_tasklet(unsigned long data)
-{
-	struct lx6464es *chip = (struct lx6464es *)data;
-	unsigned long flags;
-
-	dev_dbg(chip->card->dev, "->lx_trigger_tasklet\n");
-
-	spin_lock_irqsave(&chip->lock, flags);
-	lx_trigger_tasklet_dispatch_stream(chip, &chip->capture_stream);
-	lx_trigger_tasklet_dispatch_stream(chip, &chip->playback_stream);
-	spin_unlock_irqrestore(&chip->lock, flags);
-}
-
 static int lx_pcm_trigger_dispatch(struct lx6464es *chip,
 				   struct lx_stream *lx_stream, int cmd)
 {
 	int err = 0;
 
+	mutex_lock(&chip->lock);
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 		lx_stream->status = LX_STREAM_STATUS_SCHEDULE_RUN;
@@ -533,9 +520,12 @@
 		err = -EINVAL;
 		goto exit;
 	}
-	tasklet_schedule(&chip->trigger_tasklet);
+
+	lx_trigger_dispatch_stream(chip, &chip->capture_stream);
+	lx_trigger_dispatch_stream(chip, &chip->playback_stream);
 
 exit:
+	mutex_unlock(&chip->lock);
 	return err;
 }
 
@@ -861,6 +851,7 @@
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &lx_ops_capture);
 
 	pcm->info_flags = 0;
+	pcm->nonatomic = true;
 	strcpy(pcm->name, card_name);
 
 	err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -1009,15 +1000,9 @@
 	chip->irq = -1;
 
 	/* initialize synchronization structs */
-	spin_lock_init(&chip->lock);
-	spin_lock_init(&chip->msg_lock);
+	mutex_init(&chip->lock);
+	mutex_init(&chip->msg_lock);
 	mutex_init(&chip->setup_mutex);
-	tasklet_init(&chip->trigger_tasklet, lx_trigger_tasklet,
-		     (unsigned long)chip);
-	tasklet_init(&chip->tasklet_capture, lx_tasklet_capture,
-		     (unsigned long)chip);
-	tasklet_init(&chip->tasklet_playback, lx_tasklet_playback,
-		     (unsigned long)chip);
 
 	/* request resources */
 	err = pci_request_regions(pci, card_name);
@@ -1032,8 +1017,8 @@
 	/* dsp port */
 	chip->port_dsp_bar = pci_ioremap_bar(pci, 2);
 
-	err = request_irq(pci->irq, lx_interrupt, IRQF_SHARED,
-			  KBUILD_MODNAME, chip);
+	err = request_threaded_irq(pci->irq, lx_interrupt, lx_threaded_irq,
+				   IRQF_SHARED, KBUILD_MODNAME, chip);
 	if (err) {
 		dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
 		goto request_irq_failed;
diff --git a/sound/pci/lx6464es/lx6464es.h b/sound/pci/lx6464es/lx6464es.h
index 6792eda..1bec187 100644
--- a/sound/pci/lx6464es/lx6464es.h
+++ b/sound/pci/lx6464es/lx6464es.h
@@ -71,14 +71,10 @@
 
 	u8			mac_address[6];
 
-	spinlock_t		lock;        /* interrupt spinlock */
+	struct mutex		lock;        /* interrupt lock */
 	struct mutex            setup_mutex; /* mutex used in hw_params, open
 					      * and close */
 
-	struct tasklet_struct   trigger_tasklet; /* trigger tasklet */
-	struct tasklet_struct   tasklet_capture;
-	struct tasklet_struct   tasklet_playback;
-
 	/* ports */
 	unsigned long		port_plx;	   /* io port (size=256) */
 	void __iomem           *port_plx_remapped; /* remapped plx port */
@@ -87,8 +83,9 @@
 						    * size=8K) */
 
 	/* messaging */
-	spinlock_t		msg_lock;          /* message spinlock */
+	struct mutex		msg_lock;          /* message lock */
 	struct lx_rmh           rmh;
+	u32			irqsrc;
 
 	/* configuration */
 	uint			freq_ratio : 2;
diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c
index e8f38e5..f3d6202 100644
--- a/sound/pci/lx6464es/lx_core.c
+++ b/sound/pci/lx6464es/lx_core.c
@@ -332,27 +332,25 @@
 int lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version)
 {
 	u16 ret;
-	unsigned long flags;
 
-	spin_lock_irqsave(&chip->msg_lock, flags);
+	mutex_lock(&chip->msg_lock);
 
 	lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG);
 	ret = lx_message_send_atomic(chip, &chip->rmh);
 
 	*rdsp_version = chip->rmh.stat[1];
-	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	mutex_unlock(&chip->msg_lock);
 	return ret;
 }
 
 int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq)
 {
 	u16 ret = 0;
-	unsigned long flags;
 	u32 freq_raw = 0;
 	u32 freq = 0;
 	u32 frequency = 0;
 
-	spin_lock_irqsave(&chip->msg_lock, flags);
+	mutex_lock(&chip->msg_lock);
 
 	lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG);
 	ret = lx_message_send_atomic(chip, &chip->rmh);
@@ -370,7 +368,7 @@
 			frequency = 48000;
 	}
 
-	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	mutex_unlock(&chip->msg_lock);
 
 	*rfreq = frequency * chip->freq_ratio;
 
@@ -398,25 +396,23 @@
 
 int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran)
 {
-	unsigned long flags;
 	int ret;
 
-	spin_lock_irqsave(&chip->msg_lock, flags);
+	mutex_lock(&chip->msg_lock);
 
 	lx_message_init(&chip->rmh, CMD_02_SET_GRANULARITY);
 	chip->rmh.cmd[0] |= gran;
 
 	ret = lx_message_send_atomic(chip, &chip->rmh);
-	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	mutex_unlock(&chip->msg_lock);
 	return ret;
 }
 
 int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data)
 {
-	unsigned long flags;
 	int ret;
 
-	spin_lock_irqsave(&chip->msg_lock, flags);
+	mutex_lock(&chip->msg_lock);
 
 	lx_message_init(&chip->rmh, CMD_04_GET_EVENT);
 	chip->rmh.stat_len = 9;	/* we don't necessarily need the full length */
@@ -426,7 +422,7 @@
 	if (!ret)
 		memcpy(data, chip->rmh.stat, chip->rmh.stat_len * sizeof(u32));
 
-	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	mutex_unlock(&chip->msg_lock);
 	return ret;
 }
 
@@ -440,18 +436,16 @@
 		     int channels)
 {
 	int err;
-	unsigned long flags;
-
 	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-	spin_lock_irqsave(&chip->msg_lock, flags);
+	mutex_lock(&chip->msg_lock);
 	lx_message_init(&chip->rmh, CMD_06_ALLOCATE_PIPE);
 
 	chip->rmh.cmd[0] |= pipe_cmd;
 	chip->rmh.cmd[0] |= channels;
 
 	err = lx_message_send_atomic(chip, &chip->rmh);
-	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	mutex_unlock(&chip->msg_lock);
 
 	if (err != 0)
 		dev_err(chip->card->dev, "could not allocate pipe\n");
@@ -462,17 +456,15 @@
 int lx_pipe_release(struct lx6464es *chip, u32 pipe, int is_capture)
 {
 	int err;
-	unsigned long flags;
-
 	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-	spin_lock_irqsave(&chip->msg_lock, flags);
+	mutex_lock(&chip->msg_lock);
 	lx_message_init(&chip->rmh, CMD_07_RELEASE_PIPE);
 
 	chip->rmh.cmd[0] |= pipe_cmd;
 
 	err = lx_message_send_atomic(chip, &chip->rmh);
-	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	mutex_unlock(&chip->msg_lock);
 
 	return err;
 }
@@ -481,8 +473,6 @@
 		  u32 *r_needed, u32 *r_freed, u32 *size_array)
 {
 	int err;
-	unsigned long flags;
-
 	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
 #ifdef CONFIG_SND_DEBUG
@@ -493,7 +483,7 @@
 	*r_needed = 0;
 	*r_freed = 0;
 
-	spin_lock_irqsave(&chip->msg_lock, flags);
+	mutex_lock(&chip->msg_lock);
 	lx_message_init(&chip->rmh, CMD_08_ASK_BUFFERS);
 
 	chip->rmh.cmd[0] |= pipe_cmd;
@@ -527,7 +517,7 @@
 		}
 	}
 
-	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	mutex_unlock(&chip->msg_lock);
 	return err;
 }
 
@@ -535,36 +525,32 @@
 int lx_pipe_stop(struct lx6464es *chip, u32 pipe, int is_capture)
 {
 	int err;
-	unsigned long flags;
-
 	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-	spin_lock_irqsave(&chip->msg_lock, flags);
+	mutex_lock(&chip->msg_lock);
 	lx_message_init(&chip->rmh, CMD_09_STOP_PIPE);
 
 	chip->rmh.cmd[0] |= pipe_cmd;
 
 	err = lx_message_send_atomic(chip, &chip->rmh);
 
-	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	mutex_unlock(&chip->msg_lock);
 	return err;
 }
 
 static int lx_pipe_toggle_state(struct lx6464es *chip, u32 pipe, int is_capture)
 {
 	int err;
-	unsigned long flags;
-
 	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-	spin_lock_irqsave(&chip->msg_lock, flags);
+	mutex_lock(&chip->msg_lock);
 	lx_message_init(&chip->rmh, CMD_0B_TOGGLE_PIPE_STATE);
 
 	chip->rmh.cmd[0] |= pipe_cmd;
 
 	err = lx_message_send_atomic(chip, &chip->rmh);
 
-	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	mutex_unlock(&chip->msg_lock);
 	return err;
 }
 
@@ -600,11 +586,9 @@
 			 u64 *rsample_count)
 {
 	int err;
-	unsigned long flags;
-
 	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-	spin_lock_irqsave(&chip->msg_lock, flags);
+	mutex_lock(&chip->msg_lock);
 	lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT);
 
 	chip->rmh.cmd[0] |= pipe_cmd;
@@ -621,18 +605,16 @@
 			+ chip->rmh.stat[1]; /* lo part */
 	}
 
-	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	mutex_unlock(&chip->msg_lock);
 	return err;
 }
 
 int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate)
 {
 	int err;
-	unsigned long flags;
-
 	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-	spin_lock_irqsave(&chip->msg_lock, flags);
+	mutex_lock(&chip->msg_lock);
 	lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT);
 
 	chip->rmh.cmd[0] |= pipe_cmd;
@@ -644,7 +626,7 @@
 	else
 		*rstate = (chip->rmh.stat[0] >> PSTATE_OFFSET) & 0x0F;
 
-	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	mutex_unlock(&chip->msg_lock);
 	return err;
 }
 
@@ -686,18 +668,16 @@
 			       int is_capture, enum stream_state_t state)
 {
 	int err;
-	unsigned long flags;
-
 	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-	spin_lock_irqsave(&chip->msg_lock, flags);
+	mutex_lock(&chip->msg_lock);
 	lx_message_init(&chip->rmh, CMD_13_SET_STREAM_STATE);
 
 	chip->rmh.cmd[0] |= pipe_cmd;
 	chip->rmh.cmd[0] |= state;
 
 	err = lx_message_send_atomic(chip, &chip->rmh);
-	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	mutex_unlock(&chip->msg_lock);
 
 	return err;
 }
@@ -706,17 +686,14 @@
 			 u32 pipe, int is_capture)
 {
 	int err;
-	unsigned long flags;
-
 	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
-
 	u32 channels = runtime->channels;
 
 	if (runtime->channels != channels)
 		dev_err(chip->card->dev, "channel count mismatch: %d vs %d",
 			   runtime->channels, channels);
 
-	spin_lock_irqsave(&chip->msg_lock, flags);
+	mutex_lock(&chip->msg_lock);
 	lx_message_init(&chip->rmh, CMD_0C_DEF_STREAM);
 
 	chip->rmh.cmd[0] |= pipe_cmd;
@@ -732,7 +709,7 @@
 	chip->rmh.cmd[0] |= channels-1;
 
 	err = lx_message_send_atomic(chip, &chip->rmh);
-	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	mutex_unlock(&chip->msg_lock);
 
 	return err;
 }
@@ -741,11 +718,9 @@
 		    int *rstate)
 {
 	int err;
-	unsigned long flags;
-
 	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-	spin_lock_irqsave(&chip->msg_lock, flags);
+	mutex_lock(&chip->msg_lock);
 	lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT);
 
 	chip->rmh.cmd[0] |= pipe_cmd;
@@ -754,7 +729,7 @@
 
 	*rstate = (chip->rmh.stat[0] & SF_START) ? START_STATE : PAUSE_STATE;
 
-	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	mutex_unlock(&chip->msg_lock);
 	return err;
 }
 
@@ -762,11 +737,9 @@
 			      u64 *r_bytepos)
 {
 	int err;
-	unsigned long flags;
-
 	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-	spin_lock_irqsave(&chip->msg_lock, flags);
+	mutex_lock(&chip->msg_lock);
 	lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT);
 
 	chip->rmh.cmd[0] |= pipe_cmd;
@@ -777,7 +750,7 @@
 		      << 32)	     /* hi part */
 		+ chip->rmh.stat[1]; /* lo part */
 
-	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	mutex_unlock(&chip->msg_lock);
 	return err;
 }
 
@@ -787,11 +760,9 @@
 		   u32 *r_buffer_index)
 {
 	int err;
-	unsigned long flags;
-
 	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-	spin_lock_irqsave(&chip->msg_lock, flags);
+	mutex_lock(&chip->msg_lock);
 	lx_message_init(&chip->rmh, CMD_0F_UPDATE_BUFFER);
 
 	chip->rmh.cmd[0] |= pipe_cmd;
@@ -828,7 +799,7 @@
 			"lx_buffer_give EB_CMD_REFUSED\n");
 
  done:
-	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	mutex_unlock(&chip->msg_lock);
 	return err;
 }
 
@@ -836,11 +807,9 @@
 		   u32 *r_buffer_size)
 {
 	int err;
-	unsigned long flags;
-
 	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-	spin_lock_irqsave(&chip->msg_lock, flags);
+	mutex_lock(&chip->msg_lock);
 	lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER);
 
 	chip->rmh.cmd[0] |= pipe_cmd;
@@ -852,7 +821,7 @@
 	if (err == 0)
 		*r_buffer_size = chip->rmh.stat[0]  & MASK_DATA_SIZE;
 
-	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	mutex_unlock(&chip->msg_lock);
 	return err;
 }
 
@@ -860,11 +829,9 @@
 		     u32 buffer_index)
 {
 	int err;
-	unsigned long flags;
-
 	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-	spin_lock_irqsave(&chip->msg_lock, flags);
+	mutex_lock(&chip->msg_lock);
 	lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER);
 
 	chip->rmh.cmd[0] |= pipe_cmd;
@@ -872,7 +839,7 @@
 
 	err = lx_message_send_atomic(chip, &chip->rmh);
 
-	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	mutex_unlock(&chip->msg_lock);
 	return err;
 }
 
@@ -885,12 +852,10 @@
 int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute)
 {
 	int err;
-	unsigned long flags;
-
 	/* bit set to 1: channel muted */
 	u64 mute_mask = unmute ? 0 : 0xFFFFFFFFFFFFFFFFLLU;
 
-	spin_lock_irqsave(&chip->msg_lock, flags);
+	mutex_lock(&chip->msg_lock);
 	lx_message_init(&chip->rmh, CMD_0D_SET_MUTE);
 
 	chip->rmh.cmd[0] |= PIPE_INFO_TO_CMD(is_capture, 0);
@@ -904,7 +869,7 @@
 
 	err = lx_message_send_atomic(chip, &chip->rmh);
 
-	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	mutex_unlock(&chip->msg_lock);
 	return err;
 }
 
@@ -931,10 +896,9 @@
 		   u32 *r_levels)
 {
 	int err = 0;
-	unsigned long flags;
 	int i;
-	spin_lock_irqsave(&chip->msg_lock, flags);
 
+	mutex_lock(&chip->msg_lock);
 	for (i = 0; i < channels; i += 4) {
 		u32 s0, s1, s2, s3;
 
@@ -959,7 +923,7 @@
 		r_levels += 4;
 	}
 
-	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	mutex_unlock(&chip->msg_lock);
 	return err;
 }
 
@@ -1075,7 +1039,6 @@
 	struct snd_pcm_substream *substream = lx_stream->stream;
 	const unsigned int is_capture = lx_stream->is_capture;
 	int err;
-	unsigned long flags;
 
 	const u32 channels = substream->runtime->channels;
 	const u32 bytes_per_frame = channels * 3;
@@ -1095,7 +1058,7 @@
 
 	dev_dbg(chip->card->dev, "->lx_interrupt_request_new_buffer\n");
 
-	spin_lock_irqsave(&chip->lock, flags);
+	mutex_lock(&chip->lock);
 
 	err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array);
 	dev_dbg(chip->card->dev,
@@ -1109,85 +1072,28 @@
 		    buffer_index, (unsigned long)buf, period_bytes);
 
 	lx_stream->frame_pos = next_pos;
-	spin_unlock_irqrestore(&chip->lock, flags);
+	mutex_unlock(&chip->lock);
 
 	return err;
 }
 
-void lx_tasklet_playback(unsigned long data)
-{
-	struct lx6464es *chip = (struct lx6464es *)data;
-	struct lx_stream *lx_stream = &chip->playback_stream;
-	int err;
-
-	dev_dbg(chip->card->dev, "->lx_tasklet_playback\n");
-
-	err = lx_interrupt_request_new_buffer(chip, lx_stream);
-	if (err < 0)
-		dev_err(chip->card->dev,
-			   "cannot request new buffer for playback\n");
-
-	snd_pcm_period_elapsed(lx_stream->stream);
-}
-
-void lx_tasklet_capture(unsigned long data)
-{
-	struct lx6464es *chip = (struct lx6464es *)data;
-	struct lx_stream *lx_stream = &chip->capture_stream;
-	int err;
-
-	dev_dbg(chip->card->dev, "->lx_tasklet_capture\n");
-	err = lx_interrupt_request_new_buffer(chip, lx_stream);
-	if (err < 0)
-		dev_err(chip->card->dev,
-			   "cannot request new buffer for capture\n");
-
-	snd_pcm_period_elapsed(lx_stream->stream);
-}
-
-
-
-static int lx_interrupt_handle_audio_transfer(struct lx6464es *chip,
-					      u64 notified_in_pipe_mask,
-					      u64 notified_out_pipe_mask)
-{
-	int err = 0;
-
-	if (notified_in_pipe_mask) {
-		dev_dbg(chip->card->dev,
-			"requesting audio transfer for capture\n");
-		tasklet_hi_schedule(&chip->tasklet_capture);
-	}
-
-	if (notified_out_pipe_mask) {
-		dev_dbg(chip->card->dev,
-			"requesting audio transfer for playback\n");
-		tasklet_hi_schedule(&chip->tasklet_playback);
-	}
-
-	return err;
-}
-
-
 irqreturn_t lx_interrupt(int irq, void *dev_id)
 {
 	struct lx6464es *chip = dev_id;
 	int async_pending, async_escmd;
 	u32 irqsrc;
-
-	spin_lock(&chip->lock);
+	bool wake_thread = false;
 
 	dev_dbg(chip->card->dev,
 		"**************************************************\n");
 
 	if (!lx_interrupt_ack(chip, &irqsrc, &async_pending, &async_escmd)) {
-		spin_unlock(&chip->lock);
 		dev_dbg(chip->card->dev, "IRQ_NONE\n");
 		return IRQ_NONE; /* this device did not cause the interrupt */
 	}
 
 	if (irqsrc & MASK_SYS_STATUS_CMD_DONE)
-		goto exit;
+		return IRQ_HANDLED;
 
 	if (irqsrc & MASK_SYS_STATUS_EOBI)
 		dev_dbg(chip->card->dev, "interrupt: EOBI\n");
@@ -1202,27 +1108,8 @@
 		dev_dbg(chip->card->dev, "interrupt: ORUN\n");
 
 	if (async_pending) {
-		u64 notified_in_pipe_mask = 0;
-		u64 notified_out_pipe_mask = 0;
-		int freq_changed;
-		int err;
-
-		/* handle async events */
-		err = lx_interrupt_handle_async_events(chip, irqsrc,
-						       &freq_changed,
-						       &notified_in_pipe_mask,
-						       &notified_out_pipe_mask);
-		if (err)
-			dev_err(chip->card->dev,
-				   "error handling async events\n");
-
-		err = lx_interrupt_handle_audio_transfer(chip,
-							 notified_in_pipe_mask,
-							 notified_out_pipe_mask
-			);
-		if (err)
-			dev_err(chip->card->dev,
-				   "error during audio transfer\n");
+		wake_thread = true;
+		chip->irqsrc = irqsrc;
 	}
 
 	if (async_escmd) {
@@ -1235,9 +1122,50 @@
 		dev_dbg(chip->card->dev, "interrupt requests escmd handling\n");
 	}
 
-exit:
-	spin_unlock(&chip->lock);
-	return IRQ_HANDLED;	/* this device caused the interrupt */
+	return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED;
+}
+
+irqreturn_t lx_threaded_irq(int irq, void *dev_id)
+{
+	struct lx6464es *chip = dev_id;
+	u64 notified_in_pipe_mask = 0;
+	u64 notified_out_pipe_mask = 0;
+	int freq_changed;
+	int err;
+
+	/* handle async events */
+	err = lx_interrupt_handle_async_events(chip, chip->irqsrc,
+					       &freq_changed,
+					       &notified_in_pipe_mask,
+					       &notified_out_pipe_mask);
+	if (err)
+		dev_err(chip->card->dev, "error handling async events\n");
+
+	if (notified_in_pipe_mask) {
+		struct lx_stream *lx_stream = &chip->capture_stream;
+
+		dev_dbg(chip->card->dev,
+			"requesting audio transfer for capture\n");
+		err = lx_interrupt_request_new_buffer(chip, lx_stream);
+		if (err < 0)
+			dev_err(chip->card->dev,
+				"cannot request new buffer for capture\n");
+		snd_pcm_period_elapsed(lx_stream->stream);
+	}
+
+	if (notified_out_pipe_mask) {
+		struct lx_stream *lx_stream = &chip->playback_stream;
+
+		dev_dbg(chip->card->dev,
+			"requesting audio transfer for playback\n");
+		err = lx_interrupt_request_new_buffer(chip, lx_stream);
+		if (err < 0)
+			dev_err(chip->card->dev,
+				"cannot request new buffer for playback\n");
+		snd_pcm_period_elapsed(lx_stream->stream);
+	}
+
+	return IRQ_HANDLED;
 }
 
 
diff --git a/sound/pci/lx6464es/lx_core.h b/sound/pci/lx6464es/lx_core.h
index 5ec5e04..0cc140c 100644
--- a/sound/pci/lx6464es/lx_core.h
+++ b/sound/pci/lx6464es/lx_core.h
@@ -181,12 +181,10 @@
 
 /* interrupt handling */
 irqreturn_t lx_interrupt(int irq, void *dev_id);
+irqreturn_t lx_threaded_irq(int irq, void *dev_id);
 void lx_irq_enable(struct lx6464es *chip);
 void lx_irq_disable(struct lx6464es *chip);
 
-void lx_tasklet_capture(unsigned long data);
-void lx_tasklet_playback(unsigned long data);
-
 
 /* Stream Format Header Defines (for LIN and IEEE754) */
 #define HEADER_FMT_BASE		HEADER_FMT_BASE_LIN
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index 75fc342..1faf47e 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -986,6 +986,7 @@
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops);
 
 	pcm->info_flags = 0;
+	pcm->nonatomic = true;
 	strcpy(pcm->name, name);
 
 	preallocate_buffers(chip, pcm);
@@ -1018,6 +1019,7 @@
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops);
 
 	pcm->info_flags = 0;
+	pcm->nonatomic = true;
 	strcpy(pcm->name, name);
 
 	preallocate_buffers(chip, pcm);
@@ -1303,8 +1305,9 @@
 		}
 	}
 
-	if (request_irq(pci->irq, snd_mixart_interrupt, IRQF_SHARED,
-			KBUILD_MODNAME, mgr)) {
+	if (request_threaded_irq(pci->irq, snd_mixart_interrupt,
+				 snd_mixart_threaded_irq, IRQF_SHARED,
+				 KBUILD_MODNAME, mgr)) {
 		dev_err(&pci->dev, "unable to grab IRQ %d\n", pci->irq);
 		snd_mixart_free(mgr);
 		return -EBUSY;
@@ -1314,24 +1317,18 @@
 	sprintf(mgr->shortname, "Digigram miXart");
 	sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, irq %i", mgr->shortname, mgr->mem[0].phys, mgr->mem[1].phys, mgr->irq);
 
-	/* ISR spinlock  */
-	spin_lock_init(&mgr->lock);
-
 	/* init mailbox  */
 	mgr->msg_fifo_readptr = 0;
 	mgr->msg_fifo_writeptr = 0;
 
-	spin_lock_init(&mgr->msg_lock);
-	mutex_init(&mgr->msg_mutex);
+	mutex_init(&mgr->lock);
+	mutex_init(&mgr->msg_lock);
 	init_waitqueue_head(&mgr->msg_sleep);
 	atomic_set(&mgr->msg_processed, 0);
 
 	/* init setup mutex*/
 	mutex_init(&mgr->setup_mutex);
 
-	/* init message taslket */
-	tasklet_init(&mgr->msg_taskq, snd_mixart_msg_tasklet, (unsigned long) mgr);
-
 	/* card assignment */
 	mgr->num_cards = MIXART_MAX_CARDS; /* 4  FIXME: configurable? */
 	for (i = 0; i < mgr->num_cards; i++) {
diff --git a/sound/pci/mixart/mixart.h b/sound/pci/mixart/mixart.h
index 561634d..0cc17e0 100644
--- a/sound/pci/mixart/mixart.h
+++ b/sound/pci/mixart/mixart.h
@@ -78,22 +78,18 @@
 	char shortname[32];         /* short name of this soundcard */
 	char longname[80];          /* name of this soundcard */
 
-	/* message tasklet */
-	struct tasklet_struct msg_taskq;
-
 	/* one and only blocking message or notification may be pending  */
 	u32 pending_event;
 	wait_queue_head_t msg_sleep;
 
-	/* messages stored for tasklet */
+	/* messages fifo */
 	u32 msg_fifo[MSG_FIFO_SIZE];
 	int msg_fifo_readptr;
 	int msg_fifo_writeptr;
 	atomic_t msg_processed;       /* number of messages to be processed in takslet */
 
-	spinlock_t lock;              /* interrupt spinlock */
-	spinlock_t msg_lock;          /* mailbox spinlock */
-	struct mutex msg_mutex;   /* mutex for blocking_requests */
+	struct mutex lock;              /* interrupt lock */
+	struct mutex msg_lock;		/* mailbox lock */
 
 	struct mutex setup_mutex; /* mutex used in hw_params, open and close */
 
diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c
index 84f6745..fe80313 100644
--- a/sound/pci/mixart/mixart_core.c
+++ b/sound/pci/mixart/mixart_core.c
@@ -76,7 +76,6 @@
 static int get_msg(struct mixart_mgr *mgr, struct mixart_msg *resp,
 		   u32 msg_frame_address )
 {
-	unsigned long flags;
 	u32  headptr;
 	u32  size;
 	int  err;
@@ -84,7 +83,7 @@
 	unsigned int i;
 #endif
 
-	spin_lock_irqsave(&mgr->msg_lock, flags);
+	mutex_lock(&mgr->msg_lock);
 	err = 0;
 
 	/* copy message descriptor from miXart to driver */
@@ -133,7 +132,7 @@
 	writel_be(headptr, MIXART_MEM(mgr, MSG_OUTBOUND_FREE_HEAD));
 
  _clean_exit:
-	spin_unlock_irqrestore(&mgr->msg_lock, flags);
+	mutex_unlock(&mgr->msg_lock);
 
 	return err;
 }
@@ -243,28 +242,24 @@
 	wait_queue_t wait;
 	long timeout;
 
-	mutex_lock(&mgr->msg_mutex);
-
 	init_waitqueue_entry(&wait, current);
 
-	spin_lock_irq(&mgr->msg_lock);
+	mutex_lock(&mgr->msg_lock);
 	/* send the message */
 	err = send_msg(mgr, request, max_resp_size, 1, &msg_frame);  /* send and mark the answer pending */
 	if (err) {
-		spin_unlock_irq(&mgr->msg_lock);
-		mutex_unlock(&mgr->msg_mutex);
+		mutex_unlock(&mgr->msg_lock);
 		return err;
 	}
 
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	add_wait_queue(&mgr->msg_sleep, &wait);
-	spin_unlock_irq(&mgr->msg_lock);
+	mutex_unlock(&mgr->msg_lock);
 	timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES);
 	remove_wait_queue(&mgr->msg_sleep, &wait);
 
 	if (! timeout) {
 		/* error - no ack */
-		mutex_unlock(&mgr->msg_mutex);
 		dev_err(&mgr->pci->dev,
 			"error: no response on msg %x\n", msg_frame);
 		return -EIO;
@@ -281,7 +276,6 @@
 	if( request->message_id != resp.message_id )
 		dev_err(&mgr->pci->dev, "RESPONSE ERROR!\n");
 
-	mutex_unlock(&mgr->msg_mutex);
 	return err;
 }
 
@@ -300,34 +294,29 @@
 	if (snd_BUG_ON(notif_event & MSG_CANCEL_NOTIFY_MASK))
 		return -EINVAL;
 
-	mutex_lock(&mgr->msg_mutex);
-
 	init_waitqueue_entry(&wait, current);
 
-	spin_lock_irq(&mgr->msg_lock);
+	mutex_lock(&mgr->msg_lock);
 	/* send the message */
 	err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 1, &notif_event);  /* send and mark the notification event pending */
 	if(err) {
-		spin_unlock_irq(&mgr->msg_lock);
-		mutex_unlock(&mgr->msg_mutex);
+		mutex_unlock(&mgr->msg_lock);
 		return err;
 	}
 
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	add_wait_queue(&mgr->msg_sleep, &wait);
-	spin_unlock_irq(&mgr->msg_lock);
+	mutex_unlock(&mgr->msg_lock);
 	timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES);
 	remove_wait_queue(&mgr->msg_sleep, &wait);
 
 	if (! timeout) {
 		/* error - no ack */
-		mutex_unlock(&mgr->msg_mutex);
 		dev_err(&mgr->pci->dev,
 			"error: notification %x not received\n", notif_event);
 		return -EIO;
 	}
 
-	mutex_unlock(&mgr->msg_mutex);
 	return 0;
 }
 
@@ -335,13 +324,12 @@
 int snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *request)
 {
 	u32 message_frame;
-	unsigned long flags;
 	int err;
 
 	/* just send the message (do not mark it as a pending one) */
-	spin_lock_irqsave(&mgr->msg_lock, flags);
+	mutex_lock(&mgr->msg_lock);
 	err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 0, &message_frame);
-	spin_unlock_irqrestore(&mgr->msg_lock, flags);
+	mutex_unlock(&mgr->msg_lock);
 
 	/* the answer will be handled by snd_struct mixart_msgasklet()  */
 	atomic_inc(&mgr->msg_processed);
@@ -350,19 +338,16 @@
 }
 
 
-/* common buffer of tasklet and interrupt to send/receive messages */
+/* common buffer of interrupt to send/receive messages */
 static u32 mixart_msg_data[MSG_DEFAULT_SIZE / 4];
 
 
-void snd_mixart_msg_tasklet(unsigned long arg)
+static void snd_mixart_process_msg(struct mixart_mgr *mgr)
 {
-	struct mixart_mgr *mgr = ( struct mixart_mgr*)(arg);
 	struct mixart_msg resp;
 	u32 msg, addr, type;
 	int err;
 
-	spin_lock(&mgr->lock);
-
 	while (mgr->msg_fifo_readptr != mgr->msg_fifo_writeptr) {
 		msg = mgr->msg_fifo[mgr->msg_fifo_readptr];
 		mgr->msg_fifo_readptr++;
@@ -381,7 +366,7 @@
 			err = get_msg(mgr, &resp, addr);
 			if( err < 0 ) {
 				dev_err(&mgr->pci->dev,
-					"tasklet: error(%d) reading mf %x\n",
+					"error(%d) reading mf %x\n",
 					err, msg);
 				break;
 			}
@@ -393,12 +378,12 @@
 			case MSG_STREAM_STOP_OUTPUT_STAGE_PACKET:
 				if(mixart_msg_data[0])
 					dev_err(&mgr->pci->dev,
-						"tasklet : error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n",
+						"error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n",
 						mixart_msg_data[0]);
 				break;
 			default:
 				dev_dbg(&mgr->pci->dev,
-					"tasklet received mf(%x) : msg_id(%x) uid(%x, %x) size(%zd)\n",
+					"received mf(%x) : msg_id(%x) uid(%x, %x) size(%zd)\n",
 					   msg, resp.message_id, resp.uid.object_id, resp.uid.desc, resp.size);
 				break;
 			}
@@ -409,7 +394,7 @@
 			/* get_msg() necessary */
 		default:
 			dev_err(&mgr->pci->dev,
-				"tasklet doesn't know what to do with message %x\n",
+				"doesn't know what to do with message %x\n",
 				msg);
 		} /* switch type */
 
@@ -417,26 +402,17 @@
 		atomic_dec(&mgr->msg_processed);
 
 	} /* while there is a msg in fifo */
-
-	spin_unlock(&mgr->lock);
 }
 
 
 irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
 {
 	struct mixart_mgr *mgr = dev_id;
-	int err;
-	struct mixart_msg resp;
-
-	u32 msg;
 	u32 it_reg;
 
-	spin_lock(&mgr->lock);
-
 	it_reg = readl_le(MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET));
 	if( !(it_reg & MIXART_OIDI) ) {
 		/* this device did not cause the interrupt */
-		spin_unlock(&mgr->lock);
 		return IRQ_NONE;
 	}
 
@@ -450,6 +426,17 @@
 	/* clear interrupt */
 	writel_le( MIXART_OIDI, MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET) );
 
+	return IRQ_WAKE_THREAD;
+}
+
+irqreturn_t snd_mixart_threaded_irq(int irq, void *dev_id)
+{
+	struct mixart_mgr *mgr = dev_id;
+	int err;
+	struct mixart_msg resp;
+	u32 msg;
+
+	mutex_lock(&mgr->lock);
 	/* process interrupt */
 	while (retrieve_msg_frame(mgr, &msg)) {
 
@@ -518,9 +505,9 @@
 						stream->buf_period_frag = (u32)( sample_count - stream->abs_period_elapsed );
 
 						if(elapsed) {
-							spin_unlock(&mgr->lock);
+							mutex_unlock(&mgr->lock);
 							snd_pcm_period_elapsed(stream->substream);
-							spin_lock(&mgr->lock);
+							mutex_lock(&mgr->lock);
 						}
 					}
 				}
@@ -556,7 +543,7 @@
 			/* no break, continue ! */
 		case MSG_TYPE_ANSWER:
 			/* answer or notification to a message we are waiting for*/
-			spin_lock(&mgr->msg_lock);
+			mutex_lock(&mgr->msg_lock);
 			if( (msg & ~MSG_TYPE_MASK) == mgr->pending_event ) {
 				wake_up(&mgr->msg_sleep);
 				mgr->pending_event = 0;
@@ -566,9 +553,9 @@
 				mgr->msg_fifo[mgr->msg_fifo_writeptr] = msg;
 				mgr->msg_fifo_writeptr++;
 				mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE;
-				tasklet_schedule(&mgr->msg_taskq);
+				snd_mixart_process_msg(mgr);
 			}
-			spin_unlock(&mgr->msg_lock);
+			mutex_unlock(&mgr->msg_lock);
 			break;
 		case MSG_TYPE_REQUEST:
 		default:
@@ -582,7 +569,7 @@
 	/* allow interrupt again */
 	writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET));
 
-	spin_unlock(&mgr->lock);
+	mutex_unlock(&mgr->lock);
 
 	return IRQ_HANDLED;
 }
diff --git a/sound/pci/mixart/mixart_core.h b/sound/pci/mixart/mixart_core.h
index c919b73..d1722e5 100644
--- a/sound/pci/mixart/mixart_core.h
+++ b/sound/pci/mixart/mixart_core.h
@@ -564,7 +564,7 @@
 int  snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *request);
 
 irqreturn_t snd_mixart_interrupt(int irq, void *dev_id);
-void snd_mixart_msg_tasklet(unsigned long arg);
+irqreturn_t snd_mixart_threaded_irq(int irq, void *dev_id);
 
 void snd_mixart_reset_board(struct mixart_mgr *mgr);
 
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c
index cc0bcd9..0282824 100644
--- a/sound/pci/oxygen/oxygen_pcm.c
+++ b/sound/pci/oxygen/oxygen_pcm.c
@@ -29,6 +29,9 @@
 /* the multichannel DMA channel has a 24-bit counter */
 #define BUFFER_BYTES_MAX_MULTICH	((1 << 24) * 4)
 
+#define FIFO_BYTES			256
+#define FIFO_BYTES_MULTICH		1024
+
 #define PERIOD_BYTES_MIN		64
 
 #define DEFAULT_BUFFER_BYTES		(BUFFER_BYTES_MAX / 2)
@@ -60,6 +63,7 @@
 	.period_bytes_max = BUFFER_BYTES_MAX,
 	.periods_min = 1,
 	.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
+	.fifo_size = FIFO_BYTES,
 };
 static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
 	.info = SNDRV_PCM_INFO_MMAP |
@@ -87,6 +91,7 @@
 	.period_bytes_max = BUFFER_BYTES_MAX_MULTICH,
 	.periods_min = 1,
 	.periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN,
+	.fifo_size = FIFO_BYTES_MULTICH,
 };
 static const struct snd_pcm_hardware oxygen_ac97_hardware = {
 	.info = SNDRV_PCM_INFO_MMAP |
@@ -106,6 +111,7 @@
 	.period_bytes_max = BUFFER_BYTES_MAX,
 	.periods_min = 1,
 	.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
+	.fifo_size = FIFO_BYTES,
 };
 
 static const struct snd_pcm_hardware *const oxygen_hardware[PCM_COUNT] = {
@@ -141,6 +147,10 @@
 		runtime->hw.rates &= ~(SNDRV_PCM_RATE_32000 |
 				       SNDRV_PCM_RATE_64000);
 		runtime->hw.rate_min = 44100;
+		/* fall through */
+	case PCM_A:
+	case PCM_B:
+		runtime->hw.fifo_size = 0;
 		break;
 	case PCM_MULTICH:
 		runtime->hw.channels_max = chip->model.dac_channels_pcm;
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c
index 7b317a2..83de6fb 100644
--- a/sound/pci/oxygen/virtuoso.c
+++ b/sound/pci/oxygen/virtuoso.c
@@ -52,6 +52,7 @@
 	{ OXYGEN_PCI_SUBID(0x1043, 0x835d) },
 	{ OXYGEN_PCI_SUBID(0x1043, 0x835e) },
 	{ OXYGEN_PCI_SUBID(0x1043, 0x838e) },
+	{ OXYGEN_PCI_SUBID(0x1043, 0x8428) },
 	{ OXYGEN_PCI_SUBID(0x1043, 0x8522) },
 	{ OXYGEN_PCI_SUBID(0x1043, 0x85f4) },
 	{ OXYGEN_PCI_SUBID_BROKEN_EEPROM },
diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c
index e026059..24109d3 100644
--- a/sound/pci/oxygen/xonar_pcm179x.c
+++ b/sound/pci/oxygen/xonar_pcm179x.c
@@ -212,6 +212,9 @@
 #define GPIO_ST_MAGIC		0x0040
 #define GPIO_ST_HP		0x0080
 
+#define GPIO_XENSE_OUTPUT_ENABLE	(0x0001 | 0x0010 | 0x0020)
+#define GPIO_XENSE_SPEAKERS		0x0080
+
 #define I2C_DEVICE_PCM1796(i)	(0x98 + ((i) << 1))	/* 10011, ii, /W=0 */
 #define I2C_DEVICE_CS2000	0x9c			/* 100111, 0, /W=0 */
 
@@ -419,6 +422,7 @@
 
 	data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE;
 	data->dacs = chip->model.dac_channels_mixer / 2;
+	data->h6 = chip->model.dac_channels_mixer > 2;
 	data->hp_gain_offset = 2*-18;
 
 	pcm1796_init(chip);
@@ -499,6 +503,51 @@
 	xonar_st_init_common(chip);
 }
 
+static void xonar_xense_init(struct oxygen *chip)
+{
+	struct xonar_pcm179x *data = chip->model_data;
+
+	data->generic.ext_power_reg = OXYGEN_GPI_DATA;
+	data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
+	data->generic.ext_power_bit = GPI_EXT_POWER;
+	xonar_init_ext_power(chip);
+
+	data->generic.anti_pop_delay = 100;
+	data->has_cs2000 = 1;
+	data->cs2000_regs[CS2000_FUN_CFG_1] = CS2000_REF_CLK_DIV_1;
+
+	oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
+		OXYGEN_RATE_48000 |
+		OXYGEN_I2S_FORMAT_I2S |
+		OXYGEN_I2S_MCLK(MCLK_512) |
+		OXYGEN_I2S_BITS_16 |
+		OXYGEN_I2S_MASTER |
+		OXYGEN_I2S_BCLK_64);
+
+	xonar_st_init_i2c(chip);
+	cs2000_registers_init(chip);
+
+	data->generic.output_enable_bit = GPIO_XENSE_OUTPUT_ENABLE;
+	data->dacs = 1;
+	data->hp_gain_offset = 2*-18;
+
+	pcm1796_init(chip);
+
+	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+		GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR |
+		GPIO_ST_MAGIC | GPIO_XENSE_SPEAKERS);
+	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
+		GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR |
+		GPIO_XENSE_SPEAKERS);
+
+	xonar_init_cs53x1(chip);
+	xonar_enable_output(chip);
+
+	snd_component_add(chip->card, "PCM1796");
+	snd_component_add(chip->card, "CS5381");
+	snd_component_add(chip->card, "CS2000");
+}
+
 static void xonar_d2_cleanup(struct oxygen *chip)
 {
 	xonar_disable_output(chip);
@@ -795,11 +844,11 @@
 static int st_hp_volume_offset_info(struct snd_kcontrol *ctl,
 				    struct snd_ctl_elem_info *info)
 {
-	static const char *const names[3] = {
-		"< 64 ohms", "64-300 ohms", "300-600 ohms"
+	static const char *const names[4] = {
+		"< 32 ohms", "32-64 ohms", "64-300 ohms", "300-600 ohms"
 	};
 
-	return snd_ctl_enum_info(info, 1, 3, names);
+	return snd_ctl_enum_info(info, 1, 4, names);
 }
 
 static int st_hp_volume_offset_get(struct snd_kcontrol *ctl,
@@ -809,12 +858,14 @@
 	struct xonar_pcm179x *data = chip->model_data;
 
 	mutex_lock(&chip->mutex);
-	if (data->hp_gain_offset < 2*-6)
+	if (data->hp_gain_offset < 2*-12)
 		value->value.enumerated.item[0] = 0;
-	else if (data->hp_gain_offset < 0)
+	else if (data->hp_gain_offset < 2*-6)
 		value->value.enumerated.item[0] = 1;
-	else
+	else if (data->hp_gain_offset < 0)
 		value->value.enumerated.item[0] = 2;
+	else
+		value->value.enumerated.item[0] = 3;
 	mutex_unlock(&chip->mutex);
 	return 0;
 }
@@ -823,13 +874,13 @@
 static int st_hp_volume_offset_put(struct snd_kcontrol *ctl,
 				   struct snd_ctl_elem_value *value)
 {
-	static const s8 offsets[] = { 2*-18, 2*-6, 0 };
+	static const s8 offsets[] = { 2*-18, 2*-12, 2*-6, 0 };
 	struct oxygen *chip = ctl->private_data;
 	struct xonar_pcm179x *data = chip->model_data;
 	s8 offset;
 	int changed;
 
-	if (value->value.enumerated.item[0] > 2)
+	if (value->value.enumerated.item[0] > 3)
 		return -EINVAL;
 	offset = offsets[value->value.enumerated.item[0]];
 	mutex_lock(&chip->mutex);
@@ -859,6 +910,67 @@
 	},
 };
 
+static int xense_output_switch_get(struct snd_kcontrol *ctl,
+				   struct snd_ctl_elem_value *value)
+{
+	struct oxygen *chip = ctl->private_data;
+	u16 gpio;
+
+	gpio = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+	if (gpio & GPIO_XENSE_SPEAKERS)
+		value->value.enumerated.item[0] = 0;
+	else if (!(gpio & GPIO_XENSE_SPEAKERS) && (gpio & GPIO_ST_HP_REAR))
+		value->value.enumerated.item[0] = 1;
+	else
+		value->value.enumerated.item[0] = 2;
+	return 0;
+}
+
+static int xense_output_switch_put(struct snd_kcontrol *ctl,
+				   struct snd_ctl_elem_value *value)
+{
+	struct oxygen *chip = ctl->private_data;
+	struct xonar_pcm179x *data = chip->model_data;
+	u16 gpio_old, gpio;
+
+	mutex_lock(&chip->mutex);
+	gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+	gpio = gpio_old;
+	switch (value->value.enumerated.item[0]) {
+	case 0:
+		gpio |= GPIO_XENSE_SPEAKERS | GPIO_ST_HP_REAR;
+		break;
+	case 1:
+		gpio = (gpio | GPIO_ST_HP_REAR) & ~GPIO_XENSE_SPEAKERS;
+		break;
+	case 2:
+		gpio &= ~(GPIO_XENSE_SPEAKERS | GPIO_ST_HP_REAR);
+		break;
+	}
+	oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio);
+	data->hp_active = !(gpio & GPIO_XENSE_SPEAKERS);
+	update_pcm1796_volume(chip);
+	mutex_unlock(&chip->mutex);
+	return gpio != gpio_old;
+}
+
+static const struct snd_kcontrol_new xense_controls[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Analog Output",
+		.info = st_output_switch_info,
+		.get = xense_output_switch_get,
+		.put = xense_output_switch_put,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Headphones Impedance Playback Enum",
+		.info = st_hp_volume_offset_info,
+		.get = st_hp_volume_offset_get,
+		.put = st_hp_volume_offset_put,
+	},
+};
+
 static void xonar_line_mic_ac97_switch(struct oxygen *chip,
 				       unsigned int reg, unsigned int mute)
 {
@@ -946,6 +1058,23 @@
 	return 0;
 }
 
+static int xonar_xense_mixer_init(struct oxygen *chip)
+{
+	unsigned int i;
+	int err;
+
+	for (i = 0; i < ARRAY_SIZE(xense_controls); ++i) {
+		err = snd_ctl_add(chip->card,
+		snd_ctl_new1(&xense_controls[i], chip));
+		if (err < 0)
+			return err;
+	}
+	err = add_pcm1796_controls(chip);
+	if (err < 0)
+		return err;
+	return 0;
+}
+
 static void dump_pcm1796_registers(struct oxygen *chip,
 				   struct snd_info_buffer *buffer)
 {
@@ -1140,12 +1269,29 @@
 		break;
 	case 0x85f4:
 		chip->model = model_xonar_st;
-		/* TODO: daughterboard support */
-		chip->model.shortname = "Xonar STX II";
+		oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);
+		switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) {
+		default:
+			chip->model.shortname = "Xonar STX II";
+			break;
+		case GPIO_DB_H6:
+			chip->model.shortname = "Xonar STX II+H6";
+			chip->model.dac_channels_pcm = 8;
+			chip->model.dac_channels_mixer = 8;
+			chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128);
+			break;
+		}
 		chip->model.init = xonar_stx_init;
 		chip->model.resume = xonar_stx_resume;
 		chip->model.set_dac_params = set_pcm1796_params;
 		break;
+	case 0x8428:
+		chip->model = model_xonar_st;
+		chip->model.shortname = "Xonar Xense";
+		chip->model.chip = "AV100";
+		chip->model.init = xonar_xense_init;
+		chip->model.mixer_init = xonar_xense_mixer_init;
+		break;
 	default:
 		return -EINVAL;
 	}
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index 68a37a7..b854fc5 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -702,13 +702,11 @@
 	return 0;
 }
 
-static void pcxhr_trigger_tasklet(unsigned long arg)
+static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr)
 {
-	unsigned long flags;
 	int i, j, err;
 	struct pcxhr_pipe *pipe;
 	struct snd_pcxhr *chip;
-	struct pcxhr_mgr *mgr = (struct pcxhr_mgr*)(arg);
 	int capture_mask = 0;
 	int playback_mask = 0;
 
@@ -736,11 +734,11 @@
 	}
 	if (capture_mask == 0 && playback_mask == 0) {
 		mutex_unlock(&mgr->setup_mutex);
-		dev_err(&mgr->pci->dev, "pcxhr_trigger_tasklet : no pipes\n");
+		dev_err(&mgr->pci->dev, "pcxhr_start_linked_stream : no pipes\n");
 		return;
 	}
 
-	dev_dbg(&mgr->pci->dev, "pcxhr_trigger_tasklet : "
+	dev_dbg(&mgr->pci->dev, "pcxhr_start_linked_stream : "
 		    "playback_mask=%x capture_mask=%x\n",
 		    playback_mask, capture_mask);
 
@@ -748,7 +746,7 @@
 	err = pcxhr_set_pipe_state(mgr,  playback_mask, capture_mask, 0);
 	if (err) {
 		mutex_unlock(&mgr->setup_mutex);
-		dev_err(&mgr->pci->dev, "pcxhr_trigger_tasklet : "
+		dev_err(&mgr->pci->dev, "pcxhr_start_linked_stream : "
 			   "error stop pipes (P%x C%x)\n",
 			   playback_mask, capture_mask);
 		return;
@@ -793,7 +791,7 @@
 	err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1);
 	if (err) {
 		mutex_unlock(&mgr->setup_mutex);
-		dev_err(&mgr->pci->dev, "pcxhr_trigger_tasklet : "
+		dev_err(&mgr->pci->dev, "pcxhr_start_linked_stream : "
 			   "error start pipes (P%x C%x)\n",
 			   playback_mask, capture_mask);
 		return;
@@ -802,7 +800,7 @@
 	/* put the streams into the running state now
 	 * (increment pointer by interrupt)
 	 */
-	spin_lock_irqsave(&mgr->lock, flags);
+	mutex_lock(&mgr->lock);
 	for ( i =0; i < mgr->num_cards; i++) {
 		struct pcxhr_stream *stream;
 		chip = mgr->chip[i];
@@ -820,13 +818,13 @@
 			}
 		}
 	}
-	spin_unlock_irqrestore(&mgr->lock, flags);
+	mutex_unlock(&mgr->lock);
 
 	mutex_unlock(&mgr->setup_mutex);
 
 #ifdef CONFIG_SND_DEBUG_VERBOSE
 	do_gettimeofday(&my_tv2);
-	dev_dbg(&mgr->pci->dev, "***TRIGGER TASKLET*** TIME = %ld (err = %x)\n",
+	dev_dbg(&mgr->pci->dev, "***TRIGGER START*** TIME = %ld (err = %x)\n",
 		    (long)(my_tv2.tv_usec - my_tv1.tv_usec), err);
 #endif
 }
@@ -853,7 +851,7 @@
 					PCXHR_STREAM_STATUS_SCHEDULE_RUN;
 				snd_pcm_trigger_done(s, subs);
 			}
-			tasklet_schedule(&chip->mgr->trigger_taskq);
+			pcxhr_start_linked_stream(chip->mgr);
 		} else {
 			stream = subs->runtime->private_data;
 			snd_printdd("Only one Substream %c %d\n",
@@ -1127,20 +1125,19 @@
 
 static snd_pcm_uframes_t pcxhr_stream_pointer(struct snd_pcm_substream *subs)
 {
-	unsigned long flags;
 	u_int32_t timer_period_frag;
 	int timer_buf_periods;
 	struct snd_pcxhr *chip = snd_pcm_substream_chip(subs);
 	struct snd_pcm_runtime *runtime = subs->runtime;
 	struct pcxhr_stream *stream  = runtime->private_data;
 
-	spin_lock_irqsave(&chip->mgr->lock, flags);
+	mutex_lock(&chip->mgr->lock);
 
 	/* get the period fragment and the nb of periods in the buffer */
 	timer_period_frag = stream->timer_period_frag;
 	timer_buf_periods = stream->timer_buf_periods;
 
-	spin_unlock_irqrestore(&chip->mgr->lock, flags);
+	mutex_unlock(&chip->mgr->lock);
 
 	return (snd_pcm_uframes_t)((timer_buf_periods * runtime->period_size) +
 				   timer_period_frag);
@@ -1181,6 +1178,7 @@
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcxhr_ops);
 
 	pcm->info_flags = 0;
+	pcm->nonatomic = true;
 	strcpy(pcm->name, name);
 
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -1588,8 +1586,9 @@
 	mgr->pci = pci;
 	mgr->irq = -1;
 
-	if (request_irq(pci->irq, pcxhr_interrupt, IRQF_SHARED,
-			KBUILD_MODNAME, mgr)) {
+	if (request_threaded_irq(pci->irq, pcxhr_interrupt,
+				 pcxhr_threaded_irq, IRQF_SHARED,
+				 KBUILD_MODNAME, mgr)) {
 		dev_err(&pci->dev, "unable to grab IRQ %d\n", pci->irq);
 		pcxhr_free(mgr);
 		return -EBUSY;
@@ -1601,19 +1600,13 @@
 		mgr->shortname,
 		mgr->port[0], mgr->port[1], mgr->port[2], mgr->irq);
 
-	/* ISR spinlock  */
-	spin_lock_init(&mgr->lock);
-	spin_lock_init(&mgr->msg_lock);
+	/* ISR lock  */
+	mutex_init(&mgr->lock);
+	mutex_init(&mgr->msg_lock);
 
 	/* init setup mutex*/
 	mutex_init(&mgr->setup_mutex);
 
-	/* init taslket */
-	tasklet_init(&mgr->msg_taskq, pcxhr_msg_tasklet,
-		     (unsigned long) mgr);
-	tasklet_init(&mgr->trigger_taskq, pcxhr_trigger_tasklet,
-		     (unsigned long) mgr);
-
 	mgr->prmh = kmalloc(sizeof(*mgr->prmh) + 
 			    sizeof(u32) * (PCXHR_SIZE_MAX_LONG_STATUS -
 					   PCXHR_SIZE_MAX_STATUS),
diff --git a/sound/pci/pcxhr/pcxhr.h b/sound/pci/pcxhr/pcxhr.h
index a4c602c..9e39e50 100644
--- a/sound/pci/pcxhr/pcxhr.h
+++ b/sound/pci/pcxhr/pcxhr.h
@@ -78,14 +78,10 @@
 	char shortname[32];		/* short name of this soundcard */
 	char longname[96];		/* name of this soundcard */
 
-	/* message tasklet */
-	struct tasklet_struct msg_taskq;
 	struct pcxhr_rmh *prmh;
-	/* trigger tasklet */
-	struct tasklet_struct trigger_taskq;
 
-	spinlock_t lock;		/* interrupt spinlock */
-	spinlock_t msg_lock;		/* message spinlock */
+	struct mutex lock;		/* interrupt lock */
+	struct mutex msg_lock;		/* message lock */
 
 	struct mutex setup_mutex;	/* mutex used in hw_params, open and close */
 	struct mutex mixer_mutex;	/* mutex for mixer */
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c
index df93719..a584acb 100644
--- a/sound/pci/pcxhr/pcxhr_core.c
+++ b/sound/pci/pcxhr/pcxhr_core.c
@@ -767,11 +767,11 @@
  */
 int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
 {
-	unsigned long flags;
 	int err;
-	spin_lock_irqsave(&mgr->msg_lock, flags);
+
+	mutex_lock(&mgr->msg_lock);
 	err = pcxhr_send_msg_nolock(mgr, rmh);
-	spin_unlock_irqrestore(&mgr->msg_lock, flags);
+	mutex_unlock(&mgr->msg_lock);
 	return err;
 }
 
@@ -971,17 +971,16 @@
 				unsigned int value, int *changed)
 {
 	struct pcxhr_rmh rmh;
-	unsigned long flags;
 	int err;
 
-	spin_lock_irqsave(&mgr->msg_lock, flags);
+	mutex_lock(&mgr->msg_lock);
 	if ((mgr->io_num_reg_cont & mask) == value) {
 		dev_dbg(&mgr->pci->dev,
 			"IO_NUM_REG_CONT mask %x already is set to %x\n",
 			    mask, value);
 		if (changed)
 			*changed = 0;
-		spin_unlock_irqrestore(&mgr->msg_lock, flags);
+		mutex_unlock(&mgr->msg_lock);
 		return 0;	/* already programmed */
 	}
 	pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
@@ -996,7 +995,7 @@
 		if (changed)
 			*changed = 1;
 	}
-	spin_unlock_irqrestore(&mgr->msg_lock, flags);
+	mutex_unlock(&mgr->msg_lock);
 	return err;
 }
 
@@ -1043,22 +1042,21 @@
 }
 
 
-void pcxhr_msg_tasklet(unsigned long arg)
+static void pcxhr_msg_thread(struct pcxhr_mgr *mgr)
 {
-	struct pcxhr_mgr *mgr = (struct pcxhr_mgr *)(arg);
 	struct pcxhr_rmh *prmh = mgr->prmh;
 	int err;
 	int i, j;
 
 	if (mgr->src_it_dsp & PCXHR_IRQ_FREQ_CHANGE)
 		dev_dbg(&mgr->pci->dev,
-			"TASKLET : PCXHR_IRQ_FREQ_CHANGE event occurred\n");
+			"PCXHR_IRQ_FREQ_CHANGE event occurred\n");
 	if (mgr->src_it_dsp & PCXHR_IRQ_TIME_CODE)
 		dev_dbg(&mgr->pci->dev,
-			"TASKLET : PCXHR_IRQ_TIME_CODE event occurred\n");
+			"PCXHR_IRQ_TIME_CODE event occurred\n");
 	if (mgr->src_it_dsp & PCXHR_IRQ_NOTIFY)
 		dev_dbg(&mgr->pci->dev,
-			"TASKLET : PCXHR_IRQ_NOTIFY event occurred\n");
+			"PCXHR_IRQ_NOTIFY event occurred\n");
 	if (mgr->src_it_dsp & (PCXHR_IRQ_FREQ_CHANGE | PCXHR_IRQ_TIME_CODE)) {
 		/* clear events FREQ_CHANGE and TIME_CODE */
 		pcxhr_init_rmh(prmh, CMD_TEST_IT);
@@ -1068,7 +1066,7 @@
 	}
 	if (mgr->src_it_dsp & PCXHR_IRQ_ASYNC) {
 		dev_dbg(&mgr->pci->dev,
-			"TASKLET : PCXHR_IRQ_ASYNC event occurred\n");
+			"PCXHR_IRQ_ASYNC event occurred\n");
 
 		pcxhr_init_rmh(prmh, CMD_ASYNC);
 		prmh->cmd[0] |= 1;	/* add SEL_ASYNC_EVENTS */
@@ -1076,7 +1074,7 @@
 		prmh->stat_len = PCXHR_SIZE_MAX_LONG_STATUS;
 		err = pcxhr_send_msg(mgr, prmh);
 		if (err)
-			dev_err(&mgr->pci->dev, "ERROR pcxhr_msg_tasklet=%x;\n",
+			dev_err(&mgr->pci->dev, "ERROR pcxhr_msg_thread=%x;\n",
 				   err);
 		i = 1;
 		while (i < prmh->stat_len) {
@@ -1220,9 +1218,9 @@
 		}
 
 		if (elapsed) {
-			spin_unlock(&mgr->lock);
+			mutex_unlock(&mgr->lock);
 			snd_pcm_period_elapsed(stream->substream);
-			spin_lock(&mgr->lock);
+			mutex_lock(&mgr->lock);
 		}
 	}
 }
@@ -1231,14 +1229,10 @@
 {
 	struct pcxhr_mgr *mgr = dev_id;
 	unsigned int reg;
-	int i, j;
-	struct snd_pcxhr *chip;
-
-	spin_lock(&mgr->lock);
+	bool wake_thread = false;
 
 	reg = PCXHR_INPL(mgr, PCXHR_PLX_IRQCS);
 	if (! (reg & PCXHR_IRQCS_ACTIVE_PCIDB)) {
-		spin_unlock(&mgr->lock);
 		/* this device did not cause the interrupt */
 		return IRQ_NONE;
 	}
@@ -1250,6 +1244,44 @@
 	/* timer irq occurred */
 	if (reg & PCXHR_IRQ_TIMER) {
 		int timer_toggle = reg & PCXHR_IRQ_TIMER;
+		if (timer_toggle == mgr->timer_toggle) {
+			dev_dbg(&mgr->pci->dev, "ERROR TIMER TOGGLE\n");
+			mgr->dsp_time_err++;
+		}
+
+		mgr->timer_toggle = timer_toggle;
+		mgr->src_it_dsp = reg;
+		wake_thread = true;
+	}
+
+	/* other irq's handled in the thread */
+	if (reg & PCXHR_IRQ_MASK) {
+		if (reg & PCXHR_IRQ_ASYNC) {
+			/* as we didn't request any async notifications,
+			 * some kind of xrun error will probably occurred
+			 */
+			/* better resynchronize all streams next interrupt : */
+			mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID;
+		}
+		mgr->src_it_dsp = reg;
+		wake_thread = true;
+	}
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+	if (reg & PCXHR_FATAL_DSP_ERR)
+		dev_dbg(&mgr->pci->dev, "FATAL DSP ERROR : %x\n", reg);
+#endif
+
+	return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED;
+}
+
+irqreturn_t pcxhr_threaded_irq(int irq, void *dev_id)
+{
+	struct pcxhr_mgr *mgr = dev_id;
+	int i, j;
+	struct snd_pcxhr *chip;
+
+	mutex_lock(&mgr->lock);
+	if (mgr->src_it_dsp & PCXHR_IRQ_TIMER) {
 		/* is a 24 bit counter */
 		int dsp_time_new =
 			PCXHR_INPL(mgr, PCXHR_PLX_MBOX4) & PCXHR_DSP_TIME_MASK;
@@ -1290,13 +1322,6 @@
 #endif
 		mgr->dsp_time_last = dsp_time_new;
 
-		if (timer_toggle == mgr->timer_toggle) {
-			dev_dbg(&mgr->pci->dev, "ERROR TIMER TOGGLE\n");
-			mgr->dsp_time_err++;
-		}
-		mgr->timer_toggle = timer_toggle;
-
-		reg &= ~PCXHR_IRQ_TIMER;
 		for (i = 0; i < mgr->num_cards; i++) {
 			chip = mgr->chip[i];
 			for (j = 0; j < chip->nb_streams_capt; j++)
@@ -1312,22 +1337,7 @@
 						dsp_time_diff);
 		}
 	}
-	/* other irq's handled in the tasklet */
-	if (reg & PCXHR_IRQ_MASK) {
-		if (reg & PCXHR_IRQ_ASYNC) {
-			/* as we didn't request any async notifications,
-			 * some kind of xrun error will probably occurred
-			 */
-			/* better resynchronize all streams next interrupt : */
-			mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID;
-		}
-		mgr->src_it_dsp = reg;
-		tasklet_schedule(&mgr->msg_taskq);
-	}
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-	if (reg & PCXHR_FATAL_DSP_ERR)
-		dev_dbg(&mgr->pci->dev, "FATAL DSP ERROR : %x\n", reg);
-#endif
-	spin_unlock(&mgr->lock);
-	return IRQ_HANDLED;	/* this device caused the interrupt */
+
+	pcxhr_msg_thread(mgr);
+	return IRQ_HANDLED;
 }
diff --git a/sound/pci/pcxhr/pcxhr_core.h b/sound/pci/pcxhr/pcxhr_core.h
index a81ab6b..dc267e4 100644
--- a/sound/pci/pcxhr/pcxhr_core.h
+++ b/sound/pci/pcxhr/pcxhr_core.h
@@ -200,6 +200,6 @@
 
 /* interrupt handling */
 irqreturn_t pcxhr_interrupt(int irq, void *dev_id);
-void pcxhr_msg_tasklet(unsigned long arg);
+irqreturn_t pcxhr_threaded_irq(int irq, void *dev_id);
 
 #endif /* __SOUND_PCXHR_CORE_H */
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c
index 3dc4732..c5a25e3 100644
--- a/sound/pci/vx222/vx222.c
+++ b/sound/pci/vx222/vx222.c
@@ -168,8 +168,9 @@
 	for (i = 0; i < 2; i++)
 		vx->port[i] = pci_resource_start(pci, i + 1);
 
-	if (request_irq(pci->irq, snd_vx_irq_handler, IRQF_SHARED,
-			KBUILD_MODNAME, chip)) {
+	if (request_threaded_irq(pci->irq, snd_vx_irq_handler,
+				 snd_vx_threaded_irq_handler, IRQF_SHARED,
+				 KBUILD_MODNAME, chip)) {
 		dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
 		snd_vx222_free(chip);
 		return -EBUSY;
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c
index 56bda12..07f4b33 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c
@@ -61,6 +61,7 @@
 
 static void pdacf_release(struct pcmcia_device *link)
 {
+	free_irq(link->irq, link->priv);
 	pcmcia_disable_device(link);
 }
 
@@ -220,11 +221,13 @@
 
 	ret = pcmcia_request_io(link);
 	if (ret)
-		goto failed;
+		goto failed_preirq;
 
-	ret = pcmcia_request_irq(link, pdacf_interrupt);
+	ret = request_threaded_irq(link->irq, pdacf_interrupt,
+				   pdacf_threaded_irq,
+				   IRQF_SHARED, link->devname, link->priv);
 	if (ret)
-		goto failed;
+		goto failed_preirq;
 
 	ret = pcmcia_enable_device(link);
 	if (ret)
@@ -236,7 +239,9 @@
 
 	return 0;
 
-failed:
+ failed:
+	free_irq(link->irq, link->priv);
+failed_preirq:
 	pcmcia_disable_device(link);
 	return -ENODEV;
 }
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.h b/sound/pcmcia/pdaudiocf/pdaudiocf.h
index ea41e57..e9a7d3a 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf.h
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.h
@@ -88,10 +88,9 @@
 	unsigned long port;
 	int irq;
 
-	spinlock_t reg_lock;
+	struct mutex reg_lock;
 	unsigned short regmap[8];
 	unsigned short suspend_reg_scr;
-	struct tasklet_struct tq;
 
 	spinlock_t ak4117_lock;
 	struct ak4117 *ak4117;
@@ -136,7 +135,7 @@
 #endif
 int snd_pdacf_pcm_new(struct snd_pdacf *chip);
 irqreturn_t pdacf_interrupt(int irq, void *dev);
-void pdacf_tasklet(unsigned long private_data);
+irqreturn_t pdacf_threaded_irq(int irq, void *dev);
 void pdacf_reinit(struct snd_pdacf *chip, int resume);
 
 #endif /* __PDAUDIOCF_H */
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
index ea0adfb..d724ab06 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
@@ -162,9 +162,8 @@
 	if (chip == NULL)
 		return NULL;
 	chip->card = card;
-	spin_lock_init(&chip->reg_lock);
+	mutex_init(&chip->reg_lock);
 	spin_lock_init(&chip->ak4117_lock);
-	tasklet_init(&chip->tq, pdacf_tasklet, (unsigned long)chip);
 	card->private_data = chip;
 
 	pdacf_proc_init(chip);
@@ -174,19 +173,18 @@
 static void snd_pdacf_ak4117_change(struct ak4117 *ak4117, unsigned char c0, unsigned char c1)
 {
 	struct snd_pdacf *chip = ak4117->change_callback_private;
-	unsigned long flags;
 	u16 val;
 
 	if (!(c0 & AK4117_UNLCK))
 		return;
-	spin_lock_irqsave(&chip->reg_lock, flags);
+	mutex_lock(&chip->reg_lock);
 	val = chip->regmap[PDAUDIOCF_REG_SCR>>1];
 	if (ak4117->rcs0 & AK4117_UNLCK)
 		val |= PDAUDIOCF_BLUE_LED_OFF;
 	else
 		val &= ~PDAUDIOCF_BLUE_LED_OFF;
 	pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	mutex_unlock(&chip->reg_lock);
 }
 
 int snd_pdacf_ak4117_create(struct snd_pdacf *chip)
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
index dcd3220..ecf0fbd 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
@@ -30,6 +30,7 @@
 {
 	struct snd_pdacf *chip = dev;
 	unsigned short stat;
+	bool wake_thread = false;
 
 	if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|
 				  PDAUDIOCF_STAT_IS_CONFIGURED|
@@ -41,13 +42,13 @@
 		if (stat & PDAUDIOCF_IRQOVR)	/* should never happen */
 			snd_printk(KERN_ERR "PDAUDIOCF SRAM buffer overrun detected!\n");
 		if (chip->pcm_substream)
-			tasklet_schedule(&chip->tq);
+			wake_thread = true;
 		if (!(stat & PDAUDIOCF_IRQAKM))
 			stat |= PDAUDIOCF_IRQAKM;	/* check rate */
 	}
 	if (get_irq_regs() != NULL)
 		snd_ak4117_check_rate_and_errors(chip->ak4117, 0);
-	return IRQ_HANDLED;
+	return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED;
 }
 
 static inline void pdacf_transfer_mono16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
@@ -256,16 +257,16 @@
 	}
 }
 
-void pdacf_tasklet(unsigned long private_data)
+irqreturn_t pdacf_threaded_irq(int irq, void *dev)
 {
-	struct snd_pdacf *chip = (struct snd_pdacf *) private_data;
+	struct snd_pdacf *chip = dev;
 	int size, off, cont, rdp, wdp;
 
 	if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|PDAUDIOCF_STAT_IS_CONFIGURED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
-		return;
+		return IRQ_HANDLED;
 	
 	if (chip->pcm_substream == NULL || chip->pcm_substream->runtime == NULL || !snd_pcm_running(chip->pcm_substream))
-		return;
+		return IRQ_HANDLED;
 
 	rdp = inw(chip->port + PDAUDIOCF_REG_RDP);
 	wdp = inw(chip->port + PDAUDIOCF_REG_WDP);
@@ -311,15 +312,15 @@
 		size -= cont;
 	}
 #endif
-	spin_lock(&chip->reg_lock);
+	mutex_lock(&chip->reg_lock);
 	while (chip->pcm_tdone >= chip->pcm_period) {
 		chip->pcm_hwptr += chip->pcm_period;
 		chip->pcm_hwptr %= chip->pcm_size;
 		chip->pcm_tdone -= chip->pcm_period;
-		spin_unlock(&chip->reg_lock);
+		mutex_unlock(&chip->reg_lock);
 		snd_pcm_period_elapsed(chip->pcm_substream);
-		spin_lock(&chip->reg_lock);
+		mutex_lock(&chip->reg_lock);
 	}
-	spin_unlock(&chip->reg_lock);
-	/* printk(KERN_DEBUG "TASKLET: end\n"); */
+	mutex_unlock(&chip->reg_lock);
+	return IRQ_HANDLED;
 }
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
index 43f995a..b48aa0a 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
@@ -77,7 +77,7 @@
 	default:
 		return -EINVAL;
 	}
-	spin_lock(&chip->reg_lock);
+	mutex_lock(&chip->reg_lock);
 	chip->pcm_running += inc;
 	tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);
 	if (chip->pcm_running) {
@@ -91,7 +91,7 @@
 	tmp |= val;
 	pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp);
       __end:
-	spin_unlock(&chip->reg_lock);
+	mutex_unlock(&chip->reg_lock);
 	snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_RATE);
 	return ret;
 }
@@ -296,6 +296,7 @@
 
 	pcm->private_data = chip;
 	pcm->info_flags = 0;
+	pcm->nonatomic = true;
 	strcpy(pcm->name, chip->card->shortname);
 	chip->pcm = pcm;
 	
diff --git a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c
index fe33e12..2819729 100644
--- a/sound/pcmcia/vx/vxp_ops.c
+++ b/sound/pcmcia/vx/vxp_ops.c
@@ -468,12 +468,11 @@
 void vx_set_mic_boost(struct vx_core *chip, int boost)
 {
 	struct snd_vxpocket *pchip = (struct snd_vxpocket *)chip;
-	unsigned long flags;
 
 	if (chip->chip_status & VX_STAT_IS_STALE)
 		return;
 
-	spin_lock_irqsave(&chip->lock, flags);
+	mutex_lock(&chip->lock);
 	if (pchip->regCDSP & P24_CDSP_MICS_SEL_MASK) {
 		if (boost) {
 			/* boost: 38 dB */
@@ -486,7 +485,7 @@
                 }
 		vx_outb(chip, CDSP, pchip->regCDSP);
 	}
-	spin_unlock_irqrestore(&chip->lock, flags);
+	mutex_unlock(&chip->lock);
 }
 
 /*
@@ -511,17 +510,16 @@
 void vx_set_mic_level(struct vx_core *chip, int level)
 {
 	struct snd_vxpocket *pchip = (struct snd_vxpocket *)chip;
-	unsigned long flags;
 
 	if (chip->chip_status & VX_STAT_IS_STALE)
 		return;
 
-	spin_lock_irqsave(&chip->lock, flags);
+	mutex_lock(&chip->lock);
 	if (pchip->regCDSP & VXP_CDSP_MIC_SEL_MASK) {
 		level = vx_compute_mic_level(level);
 		vx_outb(chip, MICRO, level);
 	}
-	spin_unlock_irqrestore(&chip->lock, flags);
+	mutex_unlock(&chip->lock);
 }
 
 
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c
index 786e7e1..92ec114 100644
--- a/sound/pcmcia/vx/vxpocket.c
+++ b/sound/pcmcia/vx/vxpocket.c
@@ -62,6 +62,7 @@
  */
 static void vxpocket_release(struct pcmcia_device *link)
 {
+	free_irq(link->irq, link->priv);
 	pcmcia_disable_device(link);
 }
 
@@ -227,11 +228,13 @@
 
 	ret = pcmcia_request_io(link);
 	if (ret)
-		goto failed;
+		goto failed_preirq;
 
-	ret = pcmcia_request_irq(link, snd_vx_irq_handler);
+	ret = request_threaded_irq(link->irq, snd_vx_irq_handler,
+				   snd_vx_threaded_irq_handler,
+				   IRQF_SHARED, link->devname, link->priv);
 	if (ret)
-		goto failed;
+		goto failed_preirq;
 
 	ret = pcmcia_enable_device(link);
 	if (ret)
@@ -245,7 +248,9 @@
 
 	return 0;
 
-failed:
+ failed:
+	free_irq(link->irq, link->priv);
+failed_preirq:
 	pcmcia_disable_device(link);
 	return -ENODEV;
 }
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
index 922006d..e88a6b6 100644
--- a/sound/soc/codecs/88pm860x-codec.c
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -146,7 +146,7 @@
 	struct pm860x_det	det;
 
 	int			irq[4];
-	unsigned char		name[4][MAX_NAME_LEN];
+	unsigned char		name[4][MAX_NAME_LEN+1];
 };
 
 /* -9450dB to 0dB in 150dB steps ( mute instead of -9450dB) */
@@ -1337,8 +1337,6 @@
 		}
 	}
 
-	pm860x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
 	return 0;
 
 out:
@@ -1354,7 +1352,6 @@
 
 	for (i = 3; i >= 0; i--)
 		free_irq(pm860x->irq[i], pm860x);
-	pm860x_set_bias_level(codec, SND_SOC_BIAS_OFF);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 8838838e..a68d173 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -43,6 +43,7 @@
 	select SND_SOC_ALC5623 if I2C
 	select SND_SOC_ALC5632 if I2C
 	select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
+	select SND_SOC_CS35L32 if I2C
 	select SND_SOC_CS42L51_I2C if I2C
 	select SND_SOC_CS42L52 if I2C && INPUT
 	select SND_SOC_CS42L56 if I2C && INPUT
@@ -56,7 +57,10 @@
 	select SND_SOC_DA7213 if I2C
 	select SND_SOC_DA732X if I2C
 	select SND_SOC_DA9055 if I2C
+	select SND_SOC_DMIC
 	select SND_SOC_BT_SCO
+	select SND_SOC_ES8328_SPI if SPI_MASTER
+	select SND_SOC_ES8328_I2C if I2C
 	select SND_SOC_ISABELLE if I2C
 	select SND_SOC_JZ4740_CODEC
 	select SND_SOC_LM4857 if I2C
@@ -90,6 +94,7 @@
 	select SND_SOC_SSM2518 if I2C
 	select SND_SOC_SSM2602_SPI if SPI_MASTER
 	select SND_SOC_SSM2602_I2C if I2C
+	select SND_SOC_SSM4567 if I2C
 	select SND_SOC_STA32X if I2C
 	select SND_SOC_STA350 if I2C
 	select SND_SOC_STA529 if I2C
@@ -323,6 +328,10 @@
 config SND_SOC_CQ0093VC
 	tristate
 
+config SND_SOC_CS35L32
+	tristate "Cirrus Logic CS35L32 CODEC"
+	depends on I2C
+
 config SND_SOC_CS42L51
 	tristate
 
@@ -405,6 +414,17 @@
 config SND_SOC_HDMI_CODEC
        tristate "HDMI stub CODEC"
 
+config SND_SOC_ES8328
+	tristate "Everest Semi ES8328 CODEC"
+
+config SND_SOC_ES8328_I2C
+	tristate
+	select SND_SOC_ES8328
+
+config SND_SOC_ES8328_SPI
+	tristate
+	select SND_SOC_ES8328
+
 config SND_SOC_ISABELLE
         tristate
 
@@ -464,6 +484,7 @@
 
 config SND_SOC_RT286
 	tristate
+	depends on I2C
 
 config SND_SOC_RT5631
 	tristate
@@ -520,12 +541,20 @@
 	tristate
 
 config SND_SOC_SSM2602_SPI
+	tristate "Analog Devices SSM2602 CODEC - SPI"
+	depends on SPI_MASTER
 	select SND_SOC_SSM2602
-	tristate
+	select REGMAP_SPI
 
 config SND_SOC_SSM2602_I2C
+	tristate "Analog Devices SSM2602 CODEC - I2C"
+	depends on I2C
 	select SND_SOC_SSM2602
-	tristate
+	select REGMAP_I2C
+
+config SND_SOC_SSM4567
+	tristate "Analog Devices ssm4567 amplifier driver support"
+	depends on I2C
 
 config SND_SOC_STA32X
 	tristate
@@ -712,7 +741,8 @@
 	tristate
 
 config SND_SOC_WM8978
-	tristate
+	tristate "Wolfson Microelectronics WM8978 codec"
+	depends on I2C
 
 config SND_SOC_WM8983
 	tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 20afe0f..5dce451 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -32,6 +32,7 @@
 snd-soc-ak5386-objs := ak5386.o
 snd-soc-arizona-objs := arizona.o
 snd-soc-cq93vc-objs := cq93vc.o
+snd-soc-cs35l32-objs := cs35l32.o
 snd-soc-cs42l51-objs := cs42l51.o
 snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o
 snd-soc-cs42l52-objs := cs42l52.o
@@ -49,6 +50,9 @@
 snd-soc-da9055-objs := da9055.o
 snd-soc-bt-sco-objs := bt-sco.o
 snd-soc-dmic-objs := dmic.o
+snd-soc-es8328-objs := es8328.o
+snd-soc-es8328-i2c-objs := es8328-i2c.o
+snd-soc-es8328-spi-objs := es8328-spi.o
 snd-soc-isabelle-objs := isabelle.o
 snd-soc-jz4740-codec-objs := jz4740.o
 snd-soc-l3-objs := l3.o
@@ -91,6 +95,7 @@
 snd-soc-ssm2602-objs := ssm2602.o
 snd-soc-ssm2602-spi-objs := ssm2602-spi.o
 snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o
+snd-soc-ssm4567-objs := ssm4567.o
 snd-soc-sta32x-objs := sta32x.o
 snd-soc-sta350-objs := sta350.o
 snd-soc-sta529-objs := sta529.o
@@ -203,6 +208,7 @@
 obj-$(CONFIG_SND_SOC_ALC5632)	+= snd-soc-alc5632.o
 obj-$(CONFIG_SND_SOC_ARIZONA)	+= snd-soc-arizona.o
 obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
+obj-$(CONFIG_SND_SOC_CS35L32)	+= snd-soc-cs35l32.o
 obj-$(CONFIG_SND_SOC_CS42L51)	+= snd-soc-cs42l51.o
 obj-$(CONFIG_SND_SOC_CS42L51_I2C)	+= snd-soc-cs42l51-i2c.o
 obj-$(CONFIG_SND_SOC_CS42L52)	+= snd-soc-cs42l52.o
@@ -220,6 +226,9 @@
 obj-$(CONFIG_SND_SOC_DA9055)	+= snd-soc-da9055.o
 obj-$(CONFIG_SND_SOC_BT_SCO)	+= snd-soc-bt-sco.o
 obj-$(CONFIG_SND_SOC_DMIC)	+= snd-soc-dmic.o
+obj-$(CONFIG_SND_SOC_ES8328)	+= snd-soc-es8328.o
+obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
+obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
 obj-$(CONFIG_SND_SOC_ISABELLE)	+= snd-soc-isabelle.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)	+= snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
@@ -258,6 +267,7 @@
 obj-$(CONFIG_SND_SOC_SSM2602)	+= snd-soc-ssm2602.o
 obj-$(CONFIG_SND_SOC_SSM2602_SPI)	+= snd-soc-ssm2602-spi.o
 obj-$(CONFIG_SND_SOC_SSM2602_I2C)	+= snd-soc-ssm2602-i2c.o
+obj-$(CONFIG_SND_SOC_SSM4567)	+= snd-soc-ssm4567.o
 obj-$(CONFIG_SND_SOC_STA32X)   += snd-soc-sta32x.o
 obj-$(CONFIG_SND_SOC_STA350)   += snd-soc-sta350.o
 obj-$(CONFIG_SND_SOC_STA529)   += snd-soc-sta529.o
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index 1fb4402..fd43827 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -56,8 +56,7 @@
 #define GPIO31_DIR_OUTPUT			0x40
 
 /* Macrocell register definitions */
-#define AB8500_CTRL3_REG			0x0200
-#define AB8500_GPIO_DIR4_REG			0x1013
+#define AB8500_GPIO_DIR4_REG			0x13 /* Bank AB8500_MISC */
 
 /* Nr of FIR/IIR-coeff banks in ANC-block */
 #define AB8500_NR_OF_ANC_COEFF_BANKS		2
@@ -126,6 +125,8 @@
 
 /* Private data for AB8500 device-driver */
 struct ab8500_codec_drvdata {
+	struct regmap *regmap;
+
 	/* Sidetone */
 	long *sid_fir_values;
 	enum sid_state sid_status;
@@ -166,49 +167,35 @@
  */
 
 /* Read a register from the audio-bank of AB8500 */
-static unsigned int ab8500_codec_read_reg(struct snd_soc_codec *codec,
-					unsigned int reg)
+static int ab8500_codec_read_reg(void *context, unsigned int reg,
+				 unsigned int *value)
 {
+	struct device *dev = context;
 	int status;
-	unsigned int value = 0;
 
 	u8 value8;
-	status = abx500_get_register_interruptible(codec->dev, AB8500_AUDIO,
-						reg, &value8);
-	if (status < 0) {
-		dev_err(codec->dev,
-			"%s: ERROR: Register (0x%02x:0x%02x) read failed (%d).\n",
-			__func__, (u8)AB8500_AUDIO, (u8)reg, status);
-	} else {
-		dev_dbg(codec->dev,
-			"%s: Read 0x%02x from register 0x%02x:0x%02x\n",
-			__func__, value8, (u8)AB8500_AUDIO, (u8)reg);
-		value = (unsigned int)value8;
-	}
-
-	return value;
-}
-
-/* Write to a register in the audio-bank of AB8500 */
-static int ab8500_codec_write_reg(struct snd_soc_codec *codec,
-				unsigned int reg, unsigned int value)
-{
-	int status;
-
-	status = abx500_set_register_interruptible(codec->dev, AB8500_AUDIO,
-						reg, value);
-	if (status < 0)
-		dev_err(codec->dev,
-			"%s: ERROR: Register (%02x:%02x) write failed (%d).\n",
-			__func__, (u8)AB8500_AUDIO, (u8)reg, status);
-	else
-		dev_dbg(codec->dev,
-			"%s: Wrote 0x%02x into register %02x:%02x\n",
-			__func__, (u8)value, (u8)AB8500_AUDIO, (u8)reg);
+	status = abx500_get_register_interruptible(dev, AB8500_AUDIO,
+						   reg, &value8);
+	*value = (unsigned int)value8;
 
 	return status;
 }
 
+/* Write to a register in the audio-bank of AB8500 */
+static int ab8500_codec_write_reg(void *context, unsigned int reg,
+				  unsigned int value)
+{
+	struct device *dev = context;
+
+	return abx500_set_register_interruptible(dev, AB8500_AUDIO,
+						 reg, value);
+}
+
+static const struct regmap_config ab8500_codec_regmap = {
+	.reg_read = ab8500_codec_read_reg,
+	.reg_write = ab8500_codec_write_reg,
+};
+
 /*
  * Controls - DAPM
  */
@@ -1968,16 +1955,16 @@
 	dev_dbg(codec->dev, "%s: Enter.\n", __func__);
 
 	/* Set DMic-clocks to outputs */
-	status = abx500_get_register_interruptible(codec->dev, (u8)AB8500_MISC,
-						(u8)AB8500_GPIO_DIR4_REG,
+	status = abx500_get_register_interruptible(codec->dev, AB8500_MISC,
+						AB8500_GPIO_DIR4_REG,
 						&value8);
 	if (status < 0)
 		return status;
 	value = value8 | GPIO27_DIR_OUTPUT | GPIO29_DIR_OUTPUT |
 		GPIO31_DIR_OUTPUT;
 	status = abx500_set_register_interruptible(codec->dev,
-						(u8)AB8500_MISC,
-						(u8)AB8500_GPIO_DIR4_REG,
+						AB8500_MISC,
+						AB8500_GPIO_DIR4_REG,
 						value);
 	if (status < 0)
 		return status;
@@ -2565,9 +2552,6 @@
 
 static struct snd_soc_codec_driver ab8500_codec_driver = {
 	.probe =		ab8500_codec_probe,
-	.read =			ab8500_codec_read_reg,
-	.write =		ab8500_codec_write_reg,
-	.reg_word_size =	sizeof(u8),
 	.controls =		ab8500_ctrls,
 	.num_controls =		ARRAY_SIZE(ab8500_ctrls),
 	.dapm_widgets =		ab8500_dapm_widgets,
@@ -2592,6 +2576,15 @@
 	drvdata->anc_status = ANC_UNCONFIGURED;
 	dev_set_drvdata(&pdev->dev, drvdata);
 
+	drvdata->regmap = devm_regmap_init(&pdev->dev, NULL, &pdev->dev,
+					   &ab8500_codec_regmap);
+	if (IS_ERR(drvdata->regmap)) {
+		status = PTR_ERR(drvdata->regmap);
+		dev_err(&pdev->dev, "%s: Failed to allocate regmap: %d\n",
+			__func__, status);
+		return status;
+	}
+
 	dev_dbg(&pdev->dev, "%s: Register codec.\n", __func__);
 	status = snd_soc_register_codec(&pdev->dev, &ab8500_codec_driver,
 				ab8500_codec_dai,
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index e889e1b..bd9b1839 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -69,19 +69,6 @@
 	.ops = &ac97_dai_ops,
 };
 
-static unsigned int ac97_read(struct snd_soc_codec *codec,
-	unsigned int reg)
-{
-	return soc_ac97_ops->read(codec->ac97, reg);
-}
-
-static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
-	unsigned int val)
-{
-	soc_ac97_ops->write(codec->ac97, reg, val);
-	return 0;
-}
-
 static int ac97_soc_probe(struct snd_soc_codec *codec)
 {
 	struct snd_ac97_bus *ac97_bus;
@@ -122,8 +109,6 @@
 #endif
 
 static struct snd_soc_codec_driver soc_codec_dev_ac97 = {
-	.write =	ac97_write,
-	.read =		ac97_read,
 	.probe = 	ac97_soc_probe,
 	.suspend =	ac97_soc_suspend,
 	.resume =	ac97_soc_resume,
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index 1ff7d4d..7c784ad 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -1448,29 +1448,10 @@
 	return 0;
 }
 
-static int adau1373_remove(struct snd_soc_codec *codec)
-{
-	adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	return 0;
-}
-
-static int adau1373_suspend(struct snd_soc_codec *codec)
-{
-	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
-	int ret;
-
-	ret = adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	regcache_cache_only(adau1373->regmap, true);
-
-	return ret;
-}
-
 static int adau1373_resume(struct snd_soc_codec *codec)
 {
 	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
 
-	regcache_cache_only(adau1373->regmap, false);
-	adau1373_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	regcache_sync(adau1373->regmap);
 
 	return 0;
@@ -1501,8 +1482,6 @@
 
 static struct snd_soc_codec_driver adau1373_codec_driver = {
 	.probe =	adau1373_probe,
-	.remove =	adau1373_remove,
-	.suspend =	adau1373_suspend,
 	.resume =	adau1373_resume,
 	.set_bias_level = adau1373_set_bias_level,
 	.idle_bias_off = true,
diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c
index 848cab8..5518ebd 100644
--- a/sound/soc/codecs/adau1761.c
+++ b/sound/soc/codecs/adau1761.c
@@ -714,9 +714,9 @@
 
 static const struct snd_soc_codec_driver adau1761_codec_driver = {
 	.probe = adau1761_codec_probe,
-	.suspend = adau17x1_suspend,
 	.resume	= adau17x1_resume,
 	.set_bias_level	= adau1761_set_bias_level,
+	.suspend_bias_off = true,
 
 	.controls = adau1761_controls,
 	.num_controls = ARRAY_SIZE(adau1761_controls),
diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c
index 045a614..e9fc00f 100644
--- a/sound/soc/codecs/adau1781.c
+++ b/sound/soc/codecs/adau1781.c
@@ -446,9 +446,9 @@
 
 static const struct snd_soc_codec_driver adau1781_codec_driver = {
 	.probe = adau1781_codec_probe,
-	.suspend = adau17x1_suspend,
 	.resume = adau17x1_resume,
 	.set_bias_level = adau1781_set_bias_level,
+	.suspend_bias_off = true,
 
 	.controls = adau1781_controls,
 	.num_controls = ARRAY_SIZE(adau1781_controls),
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c
index 0b65970..3e16c1c 100644
--- a/sound/soc/codecs/adau17x1.c
+++ b/sound/soc/codecs/adau17x1.c
@@ -815,13 +815,6 @@
 }
 EXPORT_SYMBOL_GPL(adau17x1_add_routes);
 
-int adau17x1_suspend(struct snd_soc_codec *codec)
-{
-	codec->driver->set_bias_level(codec, SND_SOC_BIAS_OFF);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(adau17x1_suspend);
-
 int adau17x1_resume(struct snd_soc_codec *codec)
 {
 	struct adau *adau = snd_soc_codec_get_drvdata(codec);
@@ -829,7 +822,6 @@
 	if (adau->switch_mode)
 		adau->switch_mode(codec->dev);
 
-	codec->driver->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	regcache_sync(adau->regmap);
 
 	return 0;
diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h
index 3ffabaf..e4a557f 100644
--- a/sound/soc/codecs/adau17x1.h
+++ b/sound/soc/codecs/adau17x1.h
@@ -52,7 +52,6 @@
 	enum adau17x1_micbias_voltage micbias);
 bool adau17x1_readable_register(struct device *dev, unsigned int reg);
 bool adau17x1_volatile_register(struct device *dev, unsigned int reg);
-int adau17x1_suspend(struct snd_soc_codec *codec);
 int adau17x1_resume(struct snd_soc_codec *codec);
 
 extern const struct snd_soc_dai_ops adau17x1_dai_ops;
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index c43b93f..ce3cdca 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -812,42 +812,23 @@
 	/* Disable DAC zero flag */
 	regmap_write(adav80x->regmap, ADAV80X_DAC_CTRL3, 0x6);
 
-	return adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-}
-
-static int adav80x_suspend(struct snd_soc_codec *codec)
-{
-	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
-	int ret;
-
-	ret = adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	regcache_cache_only(adav80x->regmap, true);
-
-	return ret;
+	return 0;
 }
 
 static int adav80x_resume(struct snd_soc_codec *codec)
 {
 	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
 
-	regcache_cache_only(adav80x->regmap, false);
-	adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	regcache_sync(adav80x->regmap);
 
 	return 0;
 }
 
-static int adav80x_remove(struct snd_soc_codec *codec)
-{
-	return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF);
-}
-
 static struct snd_soc_codec_driver adav80x_codec_driver = {
 	.probe = adav80x_probe,
-	.remove = adav80x_remove,
-	.suspend = adav80x_suspend,
 	.resume = adav80x_resume,
 	.set_bias_level = adav80x_set_bias_level,
+	.suspend_bias_off = true,
 
 	.set_pll = adav80x_set_pll,
 	.set_sysclk = adav80x_set_sysclk,
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c
new file mode 100644
index 0000000..c125925
--- /dev/null
+++ b/sound/soc/codecs/cs35l32.c
@@ -0,0 +1,631 @@
+/*
+ * cs35l32.c -- CS35L32 ALSA SoC audio driver
+ *
+ * Copyright 2014 CirrusLogic, Inc.
+ *
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <dt-bindings/sound/cs35l32.h>
+
+#include "cs35l32.h"
+
+#define CS35L32_NUM_SUPPLIES 2
+static const char *const cs35l32_supply_names[CS35L32_NUM_SUPPLIES] = {
+	"VA",
+	"VP",
+};
+
+struct  cs35l32_private {
+	struct regmap *regmap;
+	struct snd_soc_codec *codec;
+	struct regulator_bulk_data supplies[CS35L32_NUM_SUPPLIES];
+	struct cs35l32_platform_data pdata;
+	struct gpio_desc *reset_gpio;
+};
+
+static const struct reg_default cs35l32_reg_defaults[] = {
+
+	{ 0x06, 0x04 }, /* Power Ctl 1 */
+	{ 0x07, 0xE8 }, /* Power Ctl 2 */
+	{ 0x08, 0x40 }, /* Clock Ctl */
+	{ 0x09, 0x20 }, /* Low Battery Threshold */
+	{ 0x0A, 0x00 }, /* Voltage Monitor [RO] */
+	{ 0x0B, 0x40 }, /* Conv Peak Curr Protection CTL */
+	{ 0x0C, 0x07 }, /* IMON Scaling */
+	{ 0x0D, 0x03 }, /* Audio/LED Pwr Manager */
+	{ 0x0F, 0x20 }, /* Serial Port Control */
+	{ 0x10, 0x14 }, /* Class D Amp CTL */
+	{ 0x11, 0x00 }, /* Protection Release CTL */
+	{ 0x12, 0xFF }, /* Interrupt Mask 1 */
+	{ 0x13, 0xFF }, /* Interrupt Mask 2 */
+	{ 0x14, 0xFF }, /* Interrupt Mask 3 */
+	{ 0x19, 0x00 }, /* LED Flash Mode Current */
+	{ 0x1A, 0x00 }, /* LED Movie Mode Current */
+	{ 0x1B, 0x20 }, /* LED Flash Timer */
+	{ 0x1C, 0x00 }, /* LED Flash Inhibit Current */
+};
+
+static bool cs35l32_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS35L32_DEVID_AB:
+	case CS35L32_DEVID_CD:
+	case CS35L32_DEVID_E:
+	case CS35L32_FAB_ID:
+	case CS35L32_REV_ID:
+	case CS35L32_PWRCTL1:
+	case CS35L32_PWRCTL2:
+	case CS35L32_CLK_CTL:
+	case CS35L32_BATT_THRESHOLD:
+	case CS35L32_VMON:
+	case CS35L32_BST_CPCP_CTL:
+	case CS35L32_IMON_SCALING:
+	case CS35L32_AUDIO_LED_MNGR:
+	case CS35L32_ADSP_CTL:
+	case CS35L32_CLASSD_CTL:
+	case CS35L32_PROTECT_CTL:
+	case CS35L32_INT_MASK_1:
+	case CS35L32_INT_MASK_2:
+	case CS35L32_INT_MASK_3:
+	case CS35L32_INT_STATUS_1:
+	case CS35L32_INT_STATUS_2:
+	case CS35L32_INT_STATUS_3:
+	case CS35L32_LED_STATUS:
+	case CS35L32_FLASH_MODE:
+	case CS35L32_MOVIE_MODE:
+	case CS35L32_FLASH_TIMER:
+	case CS35L32_FLASH_INHIBIT:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs35l32_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS35L32_DEVID_AB:
+	case CS35L32_DEVID_CD:
+	case CS35L32_DEVID_E:
+	case CS35L32_FAB_ID:
+	case CS35L32_REV_ID:
+	case CS35L32_INT_STATUS_1:
+	case CS35L32_INT_STATUS_2:
+	case CS35L32_INT_STATUS_3:
+	case CS35L32_LED_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs35l32_precious_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS35L32_INT_STATUS_1:
+	case CS35L32_INT_STATUS_2:
+	case CS35L32_INT_STATUS_3:
+	case CS35L32_LED_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static DECLARE_TLV_DB_SCALE(classd_ctl_tlv, 900, 300, 0);
+
+static const struct snd_kcontrol_new imon_ctl =
+	SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 6, 1, 1);
+
+static const struct snd_kcontrol_new vmon_ctl =
+	SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 7, 1, 1);
+
+static const struct snd_kcontrol_new vpmon_ctl =
+	SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 5, 1, 1);
+
+static const struct snd_kcontrol_new cs35l32_snd_controls[] = {
+	SOC_SINGLE_TLV("Speaker Volume", CS35L32_CLASSD_CTL,
+		       3, 0x04, 1, classd_ctl_tlv),
+	SOC_SINGLE("Zero Cross Switch", CS35L32_CLASSD_CTL, 2, 1, 0),
+	SOC_SINGLE("Gain Manager Switch", CS35L32_AUDIO_LED_MNGR, 3, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget cs35l32_dapm_widgets[] = {
+
+	SND_SOC_DAPM_SUPPLY("BOOST", CS35L32_PWRCTL1, 2, 1, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Speaker", CS35L32_PWRCTL1, 7, 1, NULL, 0),
+
+	SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L32_PWRCTL2, 3, 1),
+
+	SND_SOC_DAPM_INPUT("VP"),
+	SND_SOC_DAPM_INPUT("ISENSE"),
+	SND_SOC_DAPM_INPUT("VSENSE"),
+
+	SND_SOC_DAPM_SWITCH("VMON ADC", CS35L32_PWRCTL2, 7, 1, &vmon_ctl),
+	SND_SOC_DAPM_SWITCH("IMON ADC", CS35L32_PWRCTL2, 6, 1, &imon_ctl),
+	SND_SOC_DAPM_SWITCH("VPMON ADC", CS35L32_PWRCTL2, 5, 1, &vpmon_ctl),
+};
+
+static const struct snd_soc_dapm_route cs35l32_audio_map[] = {
+
+	{"Speaker", NULL, "BOOST"},
+
+	{"VMON ADC", NULL, "VSENSE"},
+	{"IMON ADC", NULL, "ISENSE"},
+	{"VPMON ADC", NULL, "VP"},
+
+	{"SDOUT", "Switch", "VMON ADC"},
+	{"SDOUT",  "Switch", "IMON ADC"},
+	{"SDOUT", "Switch", "VPMON ADC"},
+
+	{"Capture", NULL, "SDOUT"},
+};
+
+static int cs35l32_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		snd_soc_update_bits(codec, CS35L32_ADSP_CTL,
+				    CS35L32_ADSP_MASTER_MASK,
+				CS35L32_ADSP_MASTER_MASK);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		snd_soc_update_bits(codec, CS35L32_ADSP_CTL,
+				    CS35L32_ADSP_MASTER_MASK, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cs35l32_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+	struct snd_soc_codec *codec = dai->codec;
+
+	return snd_soc_update_bits(codec, CS35L32_PWRCTL2,
+					CS35L32_SDOUT_3ST, tristate << 3);
+}
+
+static const struct snd_soc_dai_ops cs35l32_ops = {
+	.set_fmt = cs35l32_set_dai_fmt,
+	.set_tristate = cs35l32_set_tristate,
+};
+
+static struct snd_soc_dai_driver cs35l32_dai[] = {
+	{
+		.name = "cs35l32-monitor",
+		.id = 0,
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = CS35L32_RATES,
+			.formats = CS35L32_FORMATS,
+		},
+		.ops = &cs35l32_ops,
+		.symmetric_rates = 1,
+	}
+};
+
+static int cs35l32_codec_set_sysclk(struct snd_soc_codec *codec,
+			      int clk_id, int source, unsigned int freq, int dir)
+{
+	unsigned int val;
+
+	switch (freq) {
+	case 6000000:
+		val = CS35L32_MCLK_RATIO;
+		break;
+	case 12000000:
+		val = CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO;
+		break;
+	case 6144000:
+		val = 0;
+		break;
+	case 12288000:
+		val = CS35L32_MCLK_DIV2_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return snd_soc_update_bits(codec, CS35L32_CLK_CTL,
+			CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO_MASK, val);
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_cs35l32 = {
+	.set_sysclk = cs35l32_codec_set_sysclk,
+
+	.dapm_widgets = cs35l32_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(cs35l32_dapm_widgets),
+	.dapm_routes = cs35l32_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(cs35l32_audio_map),
+
+	.controls = cs35l32_snd_controls,
+	.num_controls = ARRAY_SIZE(cs35l32_snd_controls),
+};
+
+/* Current and threshold powerup sequence Pg37 in datasheet */
+static const struct reg_default cs35l32_monitor_patch[] = {
+
+	{ 0x00, 0x99 },
+	{ 0x48, 0x17 },
+	{ 0x49, 0x56 },
+	{ 0x43, 0x01 },
+	{ 0x3B, 0x62 },
+	{ 0x3C, 0x80 },
+	{ 0x00, 0x00 },
+};
+
+static struct regmap_config cs35l32_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = CS35L32_MAX_REGISTER,
+	.reg_defaults = cs35l32_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(cs35l32_reg_defaults),
+	.volatile_reg = cs35l32_volatile_register,
+	.readable_reg = cs35l32_readable_register,
+	.precious_reg = cs35l32_precious_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int cs35l32_handle_of_data(struct i2c_client *i2c_client,
+				    struct cs35l32_platform_data *pdata)
+{
+	struct device_node *np = i2c_client->dev.of_node;
+	unsigned int val;
+
+	if (of_property_read_u32(np, "cirrus,sdout-share", &val) >= 0)
+		pdata->sdout_share = val;
+
+	of_property_read_u32(np, "cirrus,boost-manager", &val);
+	switch (val) {
+	case CS35L32_BOOST_MGR_AUTO:
+	case CS35L32_BOOST_MGR_AUTO_AUDIO:
+	case CS35L32_BOOST_MGR_BYPASS:
+	case CS35L32_BOOST_MGR_FIXED:
+		pdata->boost_mng = val;
+		break;
+	default:
+		dev_err(&i2c_client->dev,
+			"Wrong cirrus,boost-manager DT value %d\n", val);
+		pdata->boost_mng = CS35L32_BOOST_MGR_BYPASS;
+	}
+
+	of_property_read_u32(np, "cirrus,sdout-datacfg", &val);
+	switch (val) {
+	case CS35L32_DATA_CFG_LR_VP:
+	case CS35L32_DATA_CFG_LR_STAT:
+	case CS35L32_DATA_CFG_LR:
+	case CS35L32_DATA_CFG_LR_VPSTAT:
+		pdata->sdout_datacfg = val;
+		break;
+	default:
+		dev_err(&i2c_client->dev,
+			"Wrong cirrus,sdout-datacfg DT value %d\n", val);
+		pdata->sdout_datacfg = CS35L32_DATA_CFG_LR;
+	}
+
+	of_property_read_u32(np, "cirrus,battery-threshold", &val);
+	switch (val) {
+	case CS35L32_BATT_THRESH_3_1V:
+	case CS35L32_BATT_THRESH_3_2V:
+	case CS35L32_BATT_THRESH_3_3V:
+	case CS35L32_BATT_THRESH_3_4V:
+		pdata->batt_thresh = val;
+		break;
+	default:
+		dev_err(&i2c_client->dev,
+			"Wrong cirrus,battery-threshold DT value %d\n", val);
+		pdata->batt_thresh = CS35L32_BATT_THRESH_3_3V;
+	}
+
+	of_property_read_u32(np, "cirrus,battery-recovery", &val);
+	switch (val) {
+	case CS35L32_BATT_RECOV_3_1V:
+	case CS35L32_BATT_RECOV_3_2V:
+	case CS35L32_BATT_RECOV_3_3V:
+	case CS35L32_BATT_RECOV_3_4V:
+	case CS35L32_BATT_RECOV_3_5V:
+	case CS35L32_BATT_RECOV_3_6V:
+		pdata->batt_recov = val;
+		break;
+	default:
+		dev_err(&i2c_client->dev,
+			"Wrong cirrus,battery-recovery DT value %d\n", val);
+		pdata->batt_recov = CS35L32_BATT_RECOV_3_4V;
+	}
+
+	return 0;
+}
+
+static int cs35l32_i2c_probe(struct i2c_client *i2c_client,
+				       const struct i2c_device_id *id)
+{
+	struct cs35l32_private *cs35l32;
+	struct cs35l32_platform_data *pdata =
+		dev_get_platdata(&i2c_client->dev);
+	int ret, i;
+	unsigned int devid = 0;
+	unsigned int reg;
+
+
+	cs35l32 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs35l32_private),
+			       GFP_KERNEL);
+	if (!cs35l32) {
+		dev_err(&i2c_client->dev, "could not allocate codec\n");
+		return -ENOMEM;
+	}
+
+	i2c_set_clientdata(i2c_client, cs35l32);
+
+	cs35l32->regmap = devm_regmap_init_i2c(i2c_client, &cs35l32_regmap);
+	if (IS_ERR(cs35l32->regmap)) {
+		ret = PTR_ERR(cs35l32->regmap);
+		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
+
+	if (pdata) {
+		cs35l32->pdata = *pdata;
+	} else {
+		pdata = devm_kzalloc(&i2c_client->dev,
+				     sizeof(struct cs35l32_platform_data),
+				GFP_KERNEL);
+		if (!pdata) {
+			dev_err(&i2c_client->dev, "could not allocate pdata\n");
+			return -ENOMEM;
+		}
+		if (i2c_client->dev.of_node) {
+			ret = cs35l32_handle_of_data(i2c_client,
+						     &cs35l32->pdata);
+			if (ret != 0)
+				return ret;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(cs35l32->supplies); i++)
+		cs35l32->supplies[i].supply = cs35l32_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c_client->dev,
+				      ARRAY_SIZE(cs35l32->supplies),
+				      cs35l32->supplies);
+	if (ret != 0) {
+		dev_err(&i2c_client->dev,
+			"Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies),
+				    cs35l32->supplies);
+	if (ret != 0) {
+		dev_err(&i2c_client->dev,
+			"Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	/* Reset the Device */
+	cs35l32->reset_gpio = devm_gpiod_get(&i2c_client->dev,
+		"reset-gpios");
+	if (IS_ERR(cs35l32->reset_gpio)) {
+		ret = PTR_ERR(cs35l32->reset_gpio);
+		if (ret != -ENOENT && ret != -ENOSYS)
+			return ret;
+
+		cs35l32->reset_gpio = NULL;
+	} else {
+		ret = gpiod_direction_output(cs35l32->reset_gpio, 0);
+		if (ret)
+			return ret;
+		gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
+	}
+
+	/* initialize codec */
+	ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_AB, &reg);
+	devid = (reg & 0xFF) << 12;
+
+	ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_CD, &reg);
+	devid |= (reg & 0xFF) << 4;
+
+	ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_E, &reg);
+	devid |= (reg & 0xF0) >> 4;
+
+	if (devid != CS35L32_CHIP_ID) {
+		ret = -ENODEV;
+		dev_err(&i2c_client->dev,
+			"CS35L32 Device ID (%X). Expected %X\n",
+			devid, CS35L32_CHIP_ID);
+		return ret;
+	}
+
+	ret = regmap_read(cs35l32->regmap, CS35L32_REV_ID, &reg);
+	if (ret < 0) {
+		dev_err(&i2c_client->dev, "Get Revision ID failed\n");
+		return ret;
+	}
+
+	ret = regmap_register_patch(cs35l32->regmap, cs35l32_monitor_patch,
+				    ARRAY_SIZE(cs35l32_monitor_patch));
+	if (ret < 0) {
+		dev_err(&i2c_client->dev, "Failed to apply errata patch\n");
+		return ret;
+	}
+
+	dev_info(&i2c_client->dev,
+		 "Cirrus Logic CS35L32, Revision: %02X\n", reg & 0xFF);
+
+	/* Setup VBOOST Management */
+	if (cs35l32->pdata.boost_mng)
+		regmap_update_bits(cs35l32->regmap, CS35L32_AUDIO_LED_MNGR,
+				   CS35L32_BOOST_MASK,
+				cs35l32->pdata.boost_mng);
+
+	/* Setup ADSP Format Config */
+	if (cs35l32->pdata.sdout_share)
+		regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL,
+				    CS35L32_ADSP_SHARE_MASK,
+				cs35l32->pdata.sdout_share << 3);
+
+	/* Setup ADSP Data Configuration */
+	if (cs35l32->pdata.sdout_datacfg)
+		regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL,
+				   CS35L32_ADSP_DATACFG_MASK,
+				cs35l32->pdata.sdout_datacfg << 4);
+
+	/* Setup Low Battery Recovery  */
+	if (cs35l32->pdata.batt_recov)
+		regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD,
+				   CS35L32_BATT_REC_MASK,
+				cs35l32->pdata.batt_recov << 1);
+
+	/* Setup Low Battery Threshold */
+	if (cs35l32->pdata.batt_thresh)
+		regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD,
+				   CS35L32_BATT_THRESH_MASK,
+				cs35l32->pdata.batt_thresh << 4);
+
+	/* Power down the AMP */
+	regmap_update_bits(cs35l32->regmap, CS35L32_PWRCTL1, CS35L32_PDN_AMP,
+			    CS35L32_PDN_AMP);
+
+	/* Clear MCLK Error Bit since we don't have the clock yet */
+	ret = regmap_read(cs35l32->regmap, CS35L32_INT_STATUS_1, &reg);
+
+	ret =  snd_soc_register_codec(&i2c_client->dev,
+			&soc_codec_dev_cs35l32, cs35l32_dai,
+			ARRAY_SIZE(cs35l32_dai));
+	if (ret < 0)
+		goto err_disable;
+
+	return 0;
+
+err_disable:
+	regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies),
+			       cs35l32->supplies);
+	return ret;
+}
+
+static int cs35l32_i2c_remove(struct i2c_client *i2c_client)
+{
+	struct cs35l32_private *cs35l32 = i2c_get_clientdata(i2c_client);
+
+	snd_soc_unregister_codec(&i2c_client->dev);
+
+	/* Hold down reset */
+	if (cs35l32->reset_gpio)
+		gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int cs35l32_runtime_suspend(struct device *dev)
+{
+	struct cs35l32_private *cs35l32 = dev_get_drvdata(dev);
+
+	regcache_cache_only(cs35l32->regmap, true);
+	regcache_mark_dirty(cs35l32->regmap);
+
+	/* Hold down reset */
+	if (cs35l32->reset_gpio)
+		gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
+
+	/* remove power */
+	regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies),
+			       cs35l32->supplies);
+
+	return 0;
+}
+
+static int cs35l32_runtime_resume(struct device *dev)
+{
+	struct cs35l32_private *cs35l32 = dev_get_drvdata(dev);
+	int ret;
+
+	/* Enable power */
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies),
+				    cs35l32->supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to enable supplies: %d\n",
+			ret);
+		return ret;
+	}
+
+	if (cs35l32->reset_gpio)
+		gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
+
+	regcache_cache_only(cs35l32->regmap, false);
+	regcache_sync(cs35l32->regmap);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops cs35l32_runtime_pm = {
+	SET_RUNTIME_PM_OPS(cs35l32_runtime_suspend, cs35l32_runtime_resume,
+			   NULL)
+};
+
+static const struct of_device_id cs35l32_of_match[] = {
+	{ .compatible = "cirrus,cs35l32", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, cs35l32_of_match);
+
+
+static const struct i2c_device_id cs35l32_id[] = {
+	{"cs35l32", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, cs35l32_id);
+
+static struct i2c_driver cs35l32_i2c_driver = {
+	.driver = {
+		   .name = "cs35l32",
+		   .owner = THIS_MODULE,
+		   .pm = &cs35l32_runtime_pm,
+		   .of_match_table = cs35l32_of_match,
+		   },
+	.id_table = cs35l32_id,
+	.probe = cs35l32_i2c_probe,
+	.remove = cs35l32_i2c_remove,
+};
+
+module_i2c_driver(cs35l32_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS35L32 driver");
+MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs35l32.h b/sound/soc/codecs/cs35l32.h
new file mode 100644
index 0000000..31ab804
--- /dev/null
+++ b/sound/soc/codecs/cs35l32.h
@@ -0,0 +1,93 @@
+/*
+ * cs35l32.h -- CS35L32 ALSA SoC audio driver
+ *
+ * Copyright 2014 CirrusLogic, Inc.
+ *
+ * Author: Brian Austin <brian.austin@cirrus.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.
+ *
+ */
+
+#ifndef __CS35L32_H__
+#define __CS35L32_H__
+
+struct cs35l32_platform_data {
+	/* Low Battery Threshold */
+	unsigned int batt_thresh;
+	/* Low Battery Recovery */
+	unsigned int batt_recov;
+	/* LED Current Management*/
+	unsigned int led_mng;
+	/* Audio Gain w/ LED */
+	unsigned int audiogain_mng;
+	/* Boost Management */
+	unsigned int boost_mng;
+	/* Data CFG for DUAL device */
+	unsigned int sdout_datacfg;
+	/* SDOUT Sharing */
+	unsigned int sdout_share;
+};
+
+#define CS35L32_CHIP_ID		0x00035A32
+#define CS35L32_DEVID_AB	0x01	/* Device ID A & B [RO] */
+#define CS35L32_DEVID_CD	0x02    /* Device ID C & D [RO] */
+#define CS35L32_DEVID_E		0x03    /* Device ID E [RO] */
+#define CS35L32_FAB_ID		0x04	/* Fab ID [RO] */
+#define CS35L32_REV_ID		0x05	/* Revision ID [RO] */
+#define CS35L32_PWRCTL1		0x06    /* Power Ctl 1 */
+#define CS35L32_PWRCTL2		0x07    /* Power Ctl 2 */
+#define CS35L32_CLK_CTL		0x08	/* Clock Ctl */
+#define CS35L32_BATT_THRESHOLD	0x09	/* Low Battery Threshold */
+#define CS35L32_VMON		0x0A	/* Voltage Monitor [RO] */
+#define CS35L32_BST_CPCP_CTL	0x0B	/* Conv Peak Curr Protection CTL */
+#define CS35L32_IMON_SCALING	0x0C	/* IMON Scaling */
+#define CS35L32_AUDIO_LED_MNGR	0x0D	/* Audio/LED Pwr Manager */
+#define CS35L32_ADSP_CTL	0x0F	/* Serial Port Control */
+#define CS35L32_CLASSD_CTL	0x10	/* Class D Amp CTL */
+#define CS35L32_PROTECT_CTL	0x11	/* Protection Release CTL */
+#define CS35L32_INT_MASK_1	0x12	/* Interrupt Mask 1 */
+#define CS35L32_INT_MASK_2	0x13	/* Interrupt Mask 2 */
+#define CS35L32_INT_MASK_3	0x14	/* Interrupt Mask 3 */
+#define CS35L32_INT_STATUS_1	0x15	/* Interrupt Status 1 [RO] */
+#define CS35L32_INT_STATUS_2	0x16	/* Interrupt Status 2 [RO] */
+#define CS35L32_INT_STATUS_3	0x17	/* Interrupt Status 3 [RO] */
+#define CS35L32_LED_STATUS	0x18	/* LED Lighting Status [RO] */
+#define CS35L32_FLASH_MODE	0x19	/* LED Flash Mode Current */
+#define CS35L32_MOVIE_MODE	0x1A	/* LED Movie Mode Current */
+#define CS35L32_FLASH_TIMER	0x1B	/* LED Flash Timer */
+#define CS35L32_FLASH_INHIBIT	0x1C	/* LED Flash Inhibit Current */
+#define CS35L32_MAX_REGISTER	0x1C
+
+#define CS35L32_MCLK_DIV2	0x01
+#define CS35L32_MCLK_RATIO	0x01
+#define CS35L32_MCLKDIS		0x80
+#define CS35L32_PDN_ALL		0x01
+#define CS35L32_PDN_AMP		0x80
+#define CS35L32_PDN_BOOST	0x04
+#define CS35L32_PDN_IMON	0x40
+#define CS35L32_PDN_VMON	0x80
+#define CS35L32_PDN_VPMON	0x20
+#define CS35L32_PDN_ADSP	0x08
+
+#define CS35L32_MCLK_DIV2_MASK		0x40
+#define CS35L32_MCLK_RATIO_MASK		0x01
+#define CS35L32_MCLK_MASK		0x41
+#define CS35L32_ADSP_MASTER_MASK	0x40
+#define CS35L32_BOOST_MASK		0x03
+#define CS35L32_GAIN_MGR_MASK		0x08
+#define CS35L32_ADSP_SHARE_MASK		0x08
+#define CS35L32_ADSP_DATACFG_MASK	0x30
+#define CS35L32_SDOUT_3ST		0x80
+#define CS35L32_BATT_REC_MASK		0x0E
+#define CS35L32_BATT_THRESH_MASK	0x30
+
+#define CS35L32_RATES (SNDRV_PCM_RATE_48000)
+#define CS35L32_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | \
+			SNDRV_PCM_FMTBIT_S32_LE)
+
+
+#endif
diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c
index 69a8516..4fdd47d 100644
--- a/sound/soc/codecs/cs4265.c
+++ b/sound/soc/codecs/cs4265.c
@@ -77,6 +77,7 @@
 	case CS4265_INT_MASK:
 	case CS4265_STATUS_MODE_MSB:
 	case CS4265_STATUS_MODE_LSB:
+	case CS4265_CHIP_ID:
 		return true;
 	default:
 		return false;
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index 969167d..35fbef7 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -176,9 +176,9 @@
 	case CS42L52_BATT_LEVEL:
 	case CS42L52_SPK_STATUS:
 	case CS42L52_CHARGE_PUMP:
-		return 1;
+		return true;
 	default:
-		return 0;
+		return false;
 	}
 }
 
@@ -946,20 +946,6 @@
 		.ops = &cs42l52_ops,
 };
 
-static int cs42l52_suspend(struct snd_soc_codec *codec)
-{
-	cs42l52_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-	return 0;
-}
-
-static int cs42l52_resume(struct snd_soc_codec *codec)
-{
-	cs42l52_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-	return 0;
-}
-
 static int beep_rates[] = {
 	261, 522, 585, 667, 706, 774, 889, 1000,
 	1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
@@ -1104,8 +1090,6 @@
 
 	cs42l52_init_beep(codec);
 
-	cs42l52_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
 	cs42l52->sysclk = CS42L52_DEFAULT_CLK;
 	cs42l52->config.format = CS42L52_DEFAULT_FORMAT;
 
@@ -1115,7 +1099,6 @@
 static int cs42l52_remove(struct snd_soc_codec *codec)
 {
 	cs42l52_free_beep(codec);
-	cs42l52_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
 	return 0;
 }
@@ -1123,9 +1106,8 @@
 static struct snd_soc_codec_driver soc_codec_dev_cs42l52 = {
 	.probe = cs42l52_probe,
 	.remove = cs42l52_remove,
-	.suspend = cs42l52_suspend,
-	.resume = cs42l52_resume,
 	.set_bias_level = cs42l52_set_bias_level,
+	.suspend_bias_off = true,
 
 	.dapm_widgets = cs42l52_dapm_widgets,
 	.num_dapm_widgets = ARRAY_SIZE(cs42l52_dapm_widgets),
diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c
index c766a5a..2ddc7ac 100644
--- a/sound/soc/codecs/cs42l56.c
+++ b/sound/soc/codecs/cs42l56.c
@@ -171,9 +171,9 @@
 {
 	switch (reg) {
 	case CS42L56_INT_STATUS:
-		return 1;
+		return true;
 	default:
-		return 0;
+		return false;
 	}
 }
 
@@ -1016,20 +1016,6 @@
 		.ops = &cs42l56_ops,
 };
 
-static int cs42l56_suspend(struct snd_soc_codec *codec)
-{
-	cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-	return 0;
-}
-
-static int cs42l56_resume(struct snd_soc_codec *codec)
-{
-	cs42l56_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-	return 0;
-}
-
 static int beep_freq[] = {
 	261, 522, 585, 667, 706, 774, 889, 1000,
 	1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
@@ -1168,18 +1154,12 @@
 {
 	cs42l56_init_beep(codec);
 
-	cs42l56_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
 	return 0;
 }
 
 static int cs42l56_remove(struct snd_soc_codec *codec)
 {
-	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
-
 	cs42l56_free_beep(codec);
-	cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	regulator_bulk_free(ARRAY_SIZE(cs42l56->supplies), cs42l56->supplies);
 
 	return 0;
 }
@@ -1187,9 +1167,8 @@
 static struct snd_soc_codec_driver soc_codec_dev_cs42l56 = {
 	.probe = cs42l56_probe,
 	.remove = cs42l56_remove,
-	.suspend = cs42l56_suspend,
-	.resume = cs42l56_resume,
 	.set_bias_level = cs42l56_set_bias_level,
+	.suspend_bias_off = true,
 
 	.dapm_widgets = cs42l56_dapm_widgets,
 	.num_dapm_widgets = ARRAY_SIZE(cs42l56_dapm_widgets),
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index 0e7b9eb..2f8b946 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -1330,25 +1330,10 @@
 	 }
 };
 
-static int cs42l73_suspend(struct snd_soc_codec *codec)
-{
-	cs42l73_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-	return 0;
-}
-
-static int cs42l73_resume(struct snd_soc_codec *codec)
-{
-	cs42l73_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-	return 0;
-}
-
 static int cs42l73_probe(struct snd_soc_codec *codec)
 {
 	struct cs42l73_private *cs42l73 = snd_soc_codec_get_drvdata(codec);
 
-	cs42l73_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
 	/* Set Charge Pump Frequency */
 	if (cs42l73->pdata.chgfreq)
 		snd_soc_update_bits(codec, CS42L73_CPFCHC,
@@ -1362,18 +1347,10 @@
 	return 0;
 }
 
-static int cs42l73_remove(struct snd_soc_codec *codec)
-{
-	cs42l73_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	return 0;
-}
-
 static struct snd_soc_codec_driver soc_codec_dev_cs42l73 = {
 	.probe = cs42l73_probe,
-	.remove = cs42l73_remove,
-	.suspend = cs42l73_suspend,
-	.resume = cs42l73_resume,
 	.set_bias_level = cs42l73_set_bias_level,
+	.suspend_bias_off = true,
 
 	.dapm_widgets = cs42l73_dapm_widgets,
 	.num_dapm_widgets = ARRAY_SIZE(cs42l73_dapm_widgets),
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
index 2fae31c..61b2f9a 100644
--- a/sound/soc/codecs/da732x.c
+++ b/sound/soc/codecs/da732x.c
@@ -35,7 +35,6 @@
 
 struct da732x_priv {
 	struct regmap *regmap;
-	struct snd_soc_codec *codec;
 
 	unsigned int sysclk;
 	bool pll_en;
@@ -217,7 +216,7 @@
 		snd_soc_write(codec, DA732X_REG_CP_CTRL1, DA723X_CP_DIS);
 		break;
 	default:
-		pr_err(KERN_ERR "Wrong charge pump state\n");
+		pr_err("Wrong charge pump state\n");
 		break;
 	}
 }
@@ -1508,31 +1507,7 @@
 	return 0;
 }
 
-static int da732x_probe(struct snd_soc_codec *codec)
-{
-	struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	da732x->codec = codec;
-
-	dapm->idle_bias_off = false;
-
-	da732x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-	return 0;
-}
-
-static int da732x_remove(struct snd_soc_codec *codec)
-{
-
-	da732x_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-	return 0;
-}
-
 static struct snd_soc_codec_driver soc_codec_dev_da732x = {
-	.probe			= da732x_probe,
-	.remove			= da732x_remove,
 	.set_bias_level		= da732x_set_bias_level,
 	.controls		= da732x_snd_controls,
 	.num_controls		= ARRAY_SIZE(da732x_snd_controls),
diff --git a/sound/soc/codecs/es8328-i2c.c b/sound/soc/codecs/es8328-i2c.c
new file mode 100644
index 0000000..aae410d
--- /dev/null
+++ b/sound/soc/codecs/es8328-i2c.c
@@ -0,0 +1,60 @@
+/*
+ * es8328-i2c.c  --  ES8328 ALSA SoC I2C Audio driver
+ *
+ * Copyright 2014 Sutajio Ko-Usagi PTE LTD
+ *
+ * Author: Sean Cross <xobs@kosagi.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/i2c.h>
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "es8328.h"
+
+static const struct i2c_device_id es8328_id[] = {
+	{ "everest,es8328", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, es8328_id);
+
+static const struct of_device_id es8328_of_match[] = {
+	{ .compatible = "everest,es8328", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, es8328_of_match);
+
+static int es8328_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	return es8328_probe(&i2c->dev,
+			devm_regmap_init_i2c(i2c, &es8328_regmap_config));
+}
+
+static int es8328_i2c_remove(struct i2c_client *i2c)
+{
+	snd_soc_unregister_codec(&i2c->dev);
+	return 0;
+}
+
+static struct i2c_driver es8328_i2c_driver = {
+	.driver = {
+		.name		= "es8328",
+		.of_match_table = es8328_of_match,
+	},
+	.probe    = es8328_i2c_probe,
+	.remove   = es8328_i2c_remove,
+	.id_table = es8328_id,
+};
+
+module_i2c_driver(es8328_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ES8328 audio CODEC I2C driver");
+MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8328-spi.c b/sound/soc/codecs/es8328-spi.c
new file mode 100644
index 0000000..8fbd935
--- /dev/null
+++ b/sound/soc/codecs/es8328-spi.c
@@ -0,0 +1,49 @@
+/*
+ * es8328.c  --  ES8328 ALSA SoC SPI Audio driver
+ *
+ * Copyright 2014 Sutajio Ko-Usagi PTE LTD
+ *
+ * Author: Sean Cross <xobs@kosagi.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/regmap.h>
+#include <linux/spi/spi.h>
+#include <sound/soc.h>
+#include "es8328.h"
+
+static const struct of_device_id es8328_of_match[] = {
+	{ .compatible = "everest,es8328", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, es8328_of_match);
+
+static int es8328_spi_probe(struct spi_device *spi)
+{
+	return es8328_probe(&spi->dev,
+			devm_regmap_init_spi(spi, &es8328_regmap_config));
+}
+
+static int es8328_spi_remove(struct spi_device *spi)
+{
+	snd_soc_unregister_codec(&spi->dev);
+	return 0;
+}
+
+static struct spi_driver es8328_spi_driver = {
+	.driver = {
+		.name		= "es8328",
+		.of_match_table	= es8328_of_match,
+	},
+	.probe	= es8328_spi_probe,
+	.remove	= es8328_spi_remove,
+};
+
+module_spi_driver(es8328_spi_driver);
+MODULE_DESCRIPTION("ASoC ES8328 audio CODEC SPI driver");
+MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
new file mode 100644
index 0000000..f273251
--- /dev/null
+++ b/sound/soc/codecs/es8328.c
@@ -0,0 +1,756 @@
+/*
+ * es8328.c  --  ES8328 ALSA SoC Audio driver
+ *
+ * Copyright 2014 Sutajio Ko-Usagi PTE LTD
+ *
+ * Author: Sean Cross <xobs@kosagi.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/clk.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "es8328.h"
+
+#define ES8328_SYSCLK_RATE_1X 11289600
+#define ES8328_SYSCLK_RATE_2X 22579200
+
+/* Run the codec at 22.5792 or 11.2896 MHz to support these rates */
+static struct {
+	int rate;
+	u8 ratio;
+} mclk_ratios[] = {
+	{ 8000, 9 },
+	{11025, 7 },
+	{22050, 4 },
+	{44100, 2 },
+};
+
+/* regulator supplies for sgtl5000, VDDD is an optional external supply */
+enum sgtl5000_regulator_supplies {
+	DVDD,
+	AVDD,
+	PVDD,
+	HPVDD,
+	ES8328_SUPPLY_NUM
+};
+
+/* vddd is optional supply */
+static const char * const supply_names[ES8328_SUPPLY_NUM] = {
+	"DVDD",
+	"AVDD",
+	"PVDD",
+	"HPVDD",
+};
+
+#define ES8328_RATES (SNDRV_PCM_RATE_44100 | \
+		SNDRV_PCM_RATE_22050 | \
+		SNDRV_PCM_RATE_11025)
+#define ES8328_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+
+struct es8328_priv {
+	struct regmap *regmap;
+	struct clk *clk;
+	int playback_fs;
+	bool deemph;
+	struct regulator_bulk_data supplies[ES8328_SUPPLY_NUM];
+};
+
+/*
+ * ES8328 Controls
+ */
+
+static const char * const adcpol_txt[] = {"Normal", "L Invert", "R Invert",
+					  "L + R Invert"};
+static SOC_ENUM_SINGLE_DECL(adcpol,
+			    ES8328_ADCCONTROL6, 6, adcpol_txt);
+
+static const DECLARE_TLV_DB_SCALE(play_tlv, -3000, 100, 0);
+static const DECLARE_TLV_DB_SCALE(dac_adc_tlv, -9600, 50, 0);
+static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 300, 0);
+
+static const int deemph_settings[] = { 0, 32000, 44100, 48000 };
+
+static int es8328_set_deemph(struct snd_soc_codec *codec)
+{
+	struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
+	int val, i, best;
+
+	/*
+	 * If we're using deemphasis select the nearest available sample
+	 * rate.
+	 */
+	if (es8328->deemph) {
+		best = 1;
+		for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) {
+			if (abs(deemph_settings[i] - es8328->playback_fs) <
+			    abs(deemph_settings[best] - es8328->playback_fs))
+				best = i;
+		}
+
+		val = best << 1;
+	} else {
+		val = 0;
+	}
+
+	dev_dbg(codec->dev, "Set deemphasis %d\n", val);
+
+	return snd_soc_update_bits(codec, ES8328_DACCONTROL6, 0x6, val);
+}
+
+static int es8328_get_deemph(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.enumerated.item[0] = es8328->deemph;
+	return 0;
+}
+
+static int es8328_put_deemph(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
+	int deemph = ucontrol->value.enumerated.item[0];
+	int ret;
+
+	if (deemph > 1)
+		return -EINVAL;
+
+	ret = es8328_set_deemph(codec);
+	if (ret < 0)
+		return ret;
+
+	es8328->deemph = deemph;
+
+	return 0;
+}
+
+
+
+static const struct snd_kcontrol_new es8328_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("Capture Digital Volume",
+		ES8328_ADCCONTROL8, ES8328_ADCCONTROL9,
+		 0, 0xc0, 1, dac_adc_tlv),
+	SOC_SINGLE("Capture ZC Switch", ES8328_ADCCONTROL7, 6, 1, 0),
+
+	SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0,
+		    es8328_get_deemph, es8328_put_deemph),
+
+	SOC_ENUM("Capture Polarity", adcpol),
+
+	SOC_SINGLE_TLV("Left Mixer Left Bypass Volume",
+			ES8328_DACCONTROL17, 3, 7, 1, bypass_tlv),
+	SOC_SINGLE_TLV("Left Mixer Right Bypass Volume",
+			ES8328_DACCONTROL19, 3, 7, 1, bypass_tlv),
+	SOC_SINGLE_TLV("Right Mixer Left Bypass Volume",
+			ES8328_DACCONTROL18, 3, 7, 1, bypass_tlv),
+	SOC_SINGLE_TLV("Right Mixer Right Bypass Volume",
+			ES8328_DACCONTROL20, 3, 7, 1, bypass_tlv),
+
+	SOC_DOUBLE_R_TLV("PCM Volume",
+			ES8328_LDACVOL, ES8328_RDACVOL,
+			0, ES8328_DACVOL_MAX, 1, dac_adc_tlv),
+
+	SOC_DOUBLE_R_TLV("Output 1 Playback Volume",
+			ES8328_LOUT1VOL, ES8328_ROUT1VOL,
+			0, ES8328_OUT1VOL_MAX, 0, play_tlv),
+
+	SOC_DOUBLE_R_TLV("Output 2 Playback Volume",
+			ES8328_LOUT2VOL, ES8328_ROUT2VOL,
+			0, ES8328_OUT2VOL_MAX, 0, play_tlv),
+
+	SOC_DOUBLE_TLV("Mic PGA Volume", ES8328_ADCCONTROL1,
+			4, 0, 8, 0, mic_tlv),
+};
+
+/*
+ * DAPM Controls
+ */
+
+static const char * const es8328_line_texts[] = {
+	"Line 1", "Line 2", "PGA", "Differential"};
+
+static const struct soc_enum es8328_lline_enum =
+	SOC_ENUM_SINGLE(ES8328_DACCONTROL16, 3,
+			      ARRAY_SIZE(es8328_line_texts),
+			      es8328_line_texts);
+static const struct snd_kcontrol_new es8328_left_line_controls =
+	SOC_DAPM_ENUM("Route", es8328_lline_enum);
+
+static const struct soc_enum es8328_rline_enum =
+	SOC_ENUM_SINGLE(ES8328_DACCONTROL16, 0,
+			      ARRAY_SIZE(es8328_line_texts),
+			      es8328_line_texts);
+static const struct snd_kcontrol_new es8328_right_line_controls =
+	SOC_DAPM_ENUM("Route", es8328_lline_enum);
+
+/* Left Mixer */
+static const struct snd_kcontrol_new es8328_left_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL17, 8, 1, 0),
+	SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL17, 7, 1, 0),
+	SOC_DAPM_SINGLE("Right Playback Switch", ES8328_DACCONTROL18, 8, 1, 0),
+	SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL18, 7, 1, 0),
+};
+
+/* Right Mixer */
+static const struct snd_kcontrol_new es8328_right_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left Playback Switch", ES8328_DACCONTROL19, 8, 1, 0),
+	SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL19, 7, 1, 0),
+	SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL20, 8, 1, 0),
+	SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL20, 7, 1, 0),
+};
+
+static const char * const es8328_pga_sel[] = {
+	"Line 1", "Line 2", "Line 3", "Differential"};
+
+/* Left PGA Mux */
+static const struct soc_enum es8328_lpga_enum =
+	SOC_ENUM_SINGLE(ES8328_ADCCONTROL2, 6,
+			      ARRAY_SIZE(es8328_pga_sel),
+			      es8328_pga_sel);
+static const struct snd_kcontrol_new es8328_left_pga_controls =
+	SOC_DAPM_ENUM("Route", es8328_lpga_enum);
+
+/* Right PGA Mux */
+static const struct soc_enum es8328_rpga_enum =
+	SOC_ENUM_SINGLE(ES8328_ADCCONTROL2, 4,
+			      ARRAY_SIZE(es8328_pga_sel),
+			      es8328_pga_sel);
+static const struct snd_kcontrol_new es8328_right_pga_controls =
+	SOC_DAPM_ENUM("Route", es8328_rpga_enum);
+
+/* Differential Mux */
+static const char * const es8328_diff_sel[] = {"Line 1", "Line 2"};
+static SOC_ENUM_SINGLE_DECL(diffmux,
+			    ES8328_ADCCONTROL3, 7, es8328_diff_sel);
+static const struct snd_kcontrol_new es8328_diffmux_controls =
+	SOC_DAPM_ENUM("Route", diffmux);
+
+/* Mono ADC Mux */
+static const char * const es8328_mono_mux[] = {"Stereo", "Mono (Left)",
+	"Mono (Right)", "Digital Mono"};
+static SOC_ENUM_SINGLE_DECL(monomux,
+			    ES8328_ADCCONTROL3, 3, es8328_mono_mux);
+static const struct snd_kcontrol_new es8328_monomux_controls =
+	SOC_DAPM_ENUM("Route", monomux);
+
+static const struct snd_soc_dapm_widget es8328_dapm_widgets[] = {
+	SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
+		&es8328_diffmux_controls),
+	SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,
+		&es8328_monomux_controls),
+	SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0,
+		&es8328_monomux_controls),
+
+	SND_SOC_DAPM_MUX("Left PGA Mux", ES8328_ADCPOWER,
+			ES8328_ADCPOWER_AINL_OFF, 1,
+			&es8328_left_pga_controls),
+	SND_SOC_DAPM_MUX("Right PGA Mux", ES8328_ADCPOWER,
+			ES8328_ADCPOWER_AINR_OFF, 1,
+			&es8328_right_pga_controls),
+
+	SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0,
+		&es8328_left_line_controls),
+	SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0,
+		&es8328_right_line_controls),
+
+	SND_SOC_DAPM_ADC("Right ADC", "Right Capture", ES8328_ADCPOWER,
+			ES8328_ADCPOWER_ADCR_OFF, 1),
+	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", ES8328_ADCPOWER,
+			ES8328_ADCPOWER_ADCL_OFF, 1),
+
+	SND_SOC_DAPM_SUPPLY("Mic Bias", ES8328_ADCPOWER,
+			ES8328_ADCPOWER_MIC_BIAS_OFF, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Mic Bias Gen", ES8328_ADCPOWER,
+			ES8328_ADCPOWER_ADC_BIAS_GEN_OFF, 1, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("DAC STM", ES8328_CHIPPOWER,
+			ES8328_CHIPPOWER_DACSTM_RESET, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC STM", ES8328_CHIPPOWER,
+			ES8328_CHIPPOWER_ADCSTM_RESET, 1, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("DAC DIG", ES8328_CHIPPOWER,
+			ES8328_CHIPPOWER_DACDIG_OFF, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC DIG", ES8328_CHIPPOWER,
+			ES8328_CHIPPOWER_ADCDIG_OFF, 1, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("DAC DLL", ES8328_CHIPPOWER,
+			ES8328_CHIPPOWER_DACDLL_OFF, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC DLL", ES8328_CHIPPOWER,
+			ES8328_CHIPPOWER_ADCDLL_OFF, 1, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("ADC Vref", ES8328_CHIPPOWER,
+			ES8328_CHIPPOWER_ADCVREF_OFF, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC Vref", ES8328_CHIPPOWER,
+			ES8328_CHIPPOWER_DACVREF_OFF, 1, NULL, 0),
+
+	SND_SOC_DAPM_DAC("Right DAC", "Right Playback", ES8328_DACPOWER,
+			ES8328_DACPOWER_RDAC_OFF, 1),
+	SND_SOC_DAPM_DAC("Left DAC", "Left Playback", ES8328_DACPOWER,
+			ES8328_DACPOWER_LDAC_OFF, 1),
+
+	SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
+		&es8328_left_mixer_controls[0],
+		ARRAY_SIZE(es8328_left_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
+		&es8328_right_mixer_controls[0],
+		ARRAY_SIZE(es8328_right_mixer_controls)),
+
+	SND_SOC_DAPM_PGA("Right Out 2", ES8328_DACPOWER,
+			ES8328_DACPOWER_ROUT2_ON, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Left Out 2", ES8328_DACPOWER,
+			ES8328_DACPOWER_LOUT2_ON, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Out 1", ES8328_DACPOWER,
+			ES8328_DACPOWER_ROUT1_ON, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Left Out 1", ES8328_DACPOWER,
+			ES8328_DACPOWER_LOUT1_ON, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("LOUT1"),
+	SND_SOC_DAPM_OUTPUT("ROUT1"),
+	SND_SOC_DAPM_OUTPUT("LOUT2"),
+	SND_SOC_DAPM_OUTPUT("ROUT2"),
+
+	SND_SOC_DAPM_INPUT("LINPUT1"),
+	SND_SOC_DAPM_INPUT("LINPUT2"),
+	SND_SOC_DAPM_INPUT("RINPUT1"),
+	SND_SOC_DAPM_INPUT("RINPUT2"),
+};
+
+static const struct snd_soc_dapm_route es8328_dapm_routes[] = {
+
+	{ "Left Line Mux", "Line 1", "LINPUT1" },
+	{ "Left Line Mux", "Line 2", "LINPUT2" },
+	{ "Left Line Mux", "PGA", "Left PGA Mux" },
+	{ "Left Line Mux", "Differential", "Differential Mux" },
+
+	{ "Right Line Mux", "Line 1", "RINPUT1" },
+	{ "Right Line Mux", "Line 2", "RINPUT2" },
+	{ "Right Line Mux", "PGA", "Right PGA Mux" },
+	{ "Right Line Mux", "Differential", "Differential Mux" },
+
+	{ "Left PGA Mux", "Line 1", "LINPUT1" },
+	{ "Left PGA Mux", "Line 2", "LINPUT2" },
+	{ "Left PGA Mux", "Differential", "Differential Mux" },
+
+	{ "Right PGA Mux", "Line 1", "RINPUT1" },
+	{ "Right PGA Mux", "Line 2", "RINPUT2" },
+	{ "Right PGA Mux", "Differential", "Differential Mux" },
+
+	{ "Differential Mux", "Line 1", "LINPUT1" },
+	{ "Differential Mux", "Line 1", "RINPUT1" },
+	{ "Differential Mux", "Line 2", "LINPUT2" },
+	{ "Differential Mux", "Line 2", "RINPUT2" },
+
+	{ "Left ADC Mux", "Stereo", "Left PGA Mux" },
+	{ "Left ADC Mux", "Mono (Left)", "Left PGA Mux" },
+	{ "Left ADC Mux", "Digital Mono", "Left PGA Mux" },
+
+	{ "Right ADC Mux", "Stereo", "Right PGA Mux" },
+	{ "Right ADC Mux", "Mono (Right)", "Right PGA Mux" },
+	{ "Right ADC Mux", "Digital Mono", "Right PGA Mux" },
+
+	{ "Left ADC", NULL, "Left ADC Mux" },
+	{ "Right ADC", NULL, "Right ADC Mux" },
+
+	{ "ADC DIG", NULL, "ADC STM" },
+	{ "ADC DIG", NULL, "ADC Vref" },
+	{ "ADC DIG", NULL, "ADC DLL" },
+
+	{ "Left ADC", NULL, "ADC DIG" },
+	{ "Right ADC", NULL, "ADC DIG" },
+
+	{ "Mic Bias", NULL, "Mic Bias Gen" },
+
+	{ "Left Line Mux", "Line 1", "LINPUT1" },
+	{ "Left Line Mux", "Line 2", "LINPUT2" },
+	{ "Left Line Mux", "PGA", "Left PGA Mux" },
+	{ "Left Line Mux", "Differential", "Differential Mux" },
+
+	{ "Right Line Mux", "Line 1", "RINPUT1" },
+	{ "Right Line Mux", "Line 2", "RINPUT2" },
+	{ "Right Line Mux", "PGA", "Right PGA Mux" },
+	{ "Right Line Mux", "Differential", "Differential Mux" },
+
+	{ "Left Out 1", NULL, "Left DAC" },
+	{ "Right Out 1", NULL, "Right DAC" },
+	{ "Left Out 2", NULL, "Left DAC" },
+	{ "Right Out 2", NULL, "Right DAC" },
+
+	{ "Left Mixer", "Playback Switch", "Left DAC" },
+	{ "Left Mixer", "Left Bypass Switch", "Left Line Mux" },
+	{ "Left Mixer", "Right Playback Switch", "Right DAC" },
+	{ "Left Mixer", "Right Bypass Switch", "Right Line Mux" },
+
+	{ "Right Mixer", "Left Playback Switch", "Left DAC" },
+	{ "Right Mixer", "Left Bypass Switch", "Left Line Mux" },
+	{ "Right Mixer", "Playback Switch", "Right DAC" },
+	{ "Right Mixer", "Right Bypass Switch", "Right Line Mux" },
+
+	{ "DAC DIG", NULL, "DAC STM" },
+	{ "DAC DIG", NULL, "DAC Vref" },
+	{ "DAC DIG", NULL, "DAC DLL" },
+
+	{ "Left DAC", NULL, "DAC DIG" },
+	{ "Right DAC", NULL, "DAC DIG" },
+
+	{ "Left Out 1", NULL, "Left Mixer" },
+	{ "LOUT1", NULL, "Left Out 1" },
+	{ "Right Out 1", NULL, "Right Mixer" },
+	{ "ROUT1", NULL, "Right Out 1" },
+
+	{ "Left Out 2", NULL, "Left Mixer" },
+	{ "LOUT2", NULL, "Left Out 2" },
+	{ "Right Out 2", NULL, "Right Mixer" },
+	{ "ROUT2", NULL, "Right Out 2" },
+};
+
+static int es8328_mute(struct snd_soc_dai *dai, int mute)
+{
+	return snd_soc_update_bits(dai->codec, ES8328_DACCONTROL3,
+			ES8328_DACCONTROL3_DACMUTE,
+			mute ? ES8328_DACCONTROL3_DACMUTE : 0);
+}
+
+static int es8328_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 es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
+	int clk_rate;
+	int i;
+	int reg;
+	u8 ratio;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		reg = ES8328_DACCONTROL2;
+	else
+		reg = ES8328_ADCCONTROL5;
+
+	clk_rate = clk_get_rate(es8328->clk);
+
+	if ((clk_rate != ES8328_SYSCLK_RATE_1X) &&
+		(clk_rate != ES8328_SYSCLK_RATE_2X)) {
+		dev_err(codec->dev,
+			"%s: clock is running at %d Hz, not %d or %d Hz\n",
+			 __func__, clk_rate,
+			 ES8328_SYSCLK_RATE_1X, ES8328_SYSCLK_RATE_2X);
+		return -EINVAL;
+	}
+
+	/* find master mode MCLK to sampling frequency ratio */
+	ratio = mclk_ratios[0].rate;
+	for (i = 1; i < ARRAY_SIZE(mclk_ratios); i++)
+		if (params_rate(params) <= mclk_ratios[i].rate)
+			ratio = mclk_ratios[i].ratio;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		es8328->playback_fs = params_rate(params);
+		es8328_set_deemph(codec);
+	}
+
+	return snd_soc_update_bits(codec, reg, ES8328_RATEMASK, ratio);
+}
+
+static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
+	int clk_rate;
+	u8 mode = ES8328_DACCONTROL1_DACWL_16;
+
+	/* set master/slave audio interface */
+	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBM_CFM)
+		return -EINVAL;
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		mode |= ES8328_DACCONTROL1_DACFORMAT_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		mode |= ES8328_DACCONTROL1_DACFORMAT_RJUST;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		mode |= ES8328_DACCONTROL1_DACFORMAT_LJUST;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF)
+		return -EINVAL;
+
+	snd_soc_write(codec, ES8328_DACCONTROL1, mode);
+	snd_soc_write(codec, ES8328_ADCCONTROL4, mode);
+
+	/* Master serial port mode, with BCLK generated automatically */
+	clk_rate = clk_get_rate(es8328->clk);
+	if (clk_rate == ES8328_SYSCLK_RATE_1X)
+		snd_soc_write(codec, ES8328_MASTERMODE,
+				ES8328_MASTERMODE_MSC);
+	else
+		snd_soc_write(codec, ES8328_MASTERMODE,
+				ES8328_MASTERMODE_MCLKDIV2 |
+				ES8328_MASTERMODE_MSC);
+
+	return 0;
+}
+
+static int es8328_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/* VREF, VMID=2x50k, digital enabled */
+		snd_soc_write(codec, ES8328_CHIPPOWER, 0);
+		snd_soc_update_bits(codec, ES8328_CONTROL1,
+				ES8328_CONTROL1_VMIDSEL_MASK |
+				ES8328_CONTROL1_ENREF,
+				ES8328_CONTROL1_VMIDSEL_50k |
+				ES8328_CONTROL1_ENREF);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			snd_soc_update_bits(codec, ES8328_CONTROL1,
+					ES8328_CONTROL1_VMIDSEL_MASK |
+					ES8328_CONTROL1_ENREF,
+					ES8328_CONTROL1_VMIDSEL_5k |
+					ES8328_CONTROL1_ENREF);
+
+			/* Charge caps */
+			msleep(100);
+		}
+
+		snd_soc_write(codec, ES8328_CONTROL2,
+				ES8328_CONTROL2_OVERCURRENT_ON |
+				ES8328_CONTROL2_THERMAL_SHUTDOWN_ON);
+
+		/* VREF, VMID=2*500k, digital stopped */
+		snd_soc_update_bits(codec, ES8328_CONTROL1,
+				ES8328_CONTROL1_VMIDSEL_MASK |
+				ES8328_CONTROL1_ENREF,
+				ES8328_CONTROL1_VMIDSEL_500k |
+				ES8328_CONTROL1_ENREF);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_update_bits(codec, ES8328_CONTROL1,
+				ES8328_CONTROL1_VMIDSEL_MASK |
+				ES8328_CONTROL1_ENREF,
+				0);
+		break;
+	}
+	codec->dapm.bias_level = level;
+	return 0;
+}
+
+static const struct snd_soc_dai_ops es8328_dai_ops = {
+	.hw_params	= es8328_hw_params,
+	.digital_mute	= es8328_mute,
+	.set_fmt	= es8328_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver es8328_dai = {
+	.name = "es8328-hifi-analog",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = ES8328_RATES,
+		.formats = ES8328_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = ES8328_RATES,
+		.formats = ES8328_FORMATS,
+	},
+	.ops = &es8328_dai_ops,
+};
+
+static int es8328_suspend(struct snd_soc_codec *codec)
+{
+	struct es8328_priv *es8328;
+	int ret;
+
+	es8328 = snd_soc_codec_get_drvdata(codec);
+
+	clk_disable_unprepare(es8328->clk);
+
+	ret = regulator_bulk_disable(ARRAY_SIZE(es8328->supplies),
+			es8328->supplies);
+	if (ret) {
+		dev_err(codec->dev, "unable to disable regulators\n");
+		return ret;
+	}
+	return 0;
+}
+
+static int es8328_resume(struct snd_soc_codec *codec)
+{
+	struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
+	struct es8328_priv *es8328;
+	int ret;
+
+	es8328 = snd_soc_codec_get_drvdata(codec);
+
+	ret = clk_prepare_enable(es8328->clk);
+	if (ret) {
+		dev_err(codec->dev, "unable to enable clock\n");
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies),
+					es8328->supplies);
+	if (ret) {
+		dev_err(codec->dev, "unable to enable regulators\n");
+		return ret;
+	}
+
+	regcache_mark_dirty(regmap);
+	ret = regcache_sync(regmap);
+	if (ret) {
+		dev_err(codec->dev, "unable to sync regcache\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int es8328_codec_probe(struct snd_soc_codec *codec)
+{
+	struct es8328_priv *es8328;
+	int ret;
+
+	es8328 = snd_soc_codec_get_drvdata(codec);
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies),
+					es8328->supplies);
+	if (ret) {
+		dev_err(codec->dev, "unable to enable regulators\n");
+		return ret;
+	}
+
+	/* Setup clocks */
+	es8328->clk = devm_clk_get(codec->dev, NULL);
+	if (IS_ERR(es8328->clk)) {
+		dev_err(codec->dev, "codec clock missing or invalid\n");
+		ret = PTR_ERR(es8328->clk);
+		goto clk_fail;
+	}
+
+	ret = clk_prepare_enable(es8328->clk);
+	if (ret) {
+		dev_err(codec->dev, "unable to prepare codec clk\n");
+		goto clk_fail;
+	}
+
+	return 0;
+
+clk_fail:
+	regulator_bulk_disable(ARRAY_SIZE(es8328->supplies),
+			       es8328->supplies);
+	return ret;
+}
+
+static int es8328_remove(struct snd_soc_codec *codec)
+{
+	struct es8328_priv *es8328;
+
+	es8328 = snd_soc_codec_get_drvdata(codec);
+
+	if (es8328->clk)
+		clk_disable_unprepare(es8328->clk);
+
+	regulator_bulk_disable(ARRAY_SIZE(es8328->supplies),
+			       es8328->supplies);
+
+	return 0;
+}
+
+const struct regmap_config es8328_regmap_config = {
+	.reg_bits	= 8,
+	.val_bits	= 8,
+	.max_register	= ES8328_REG_MAX,
+	.cache_type	= REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(es8328_regmap_config);
+
+static struct snd_soc_codec_driver es8328_codec_driver = {
+	.probe		  = es8328_codec_probe,
+	.suspend	  = es8328_suspend,
+	.resume		  = es8328_resume,
+	.remove		  = es8328_remove,
+	.set_bias_level	  = es8328_set_bias_level,
+	.suspend_bias_off = true,
+
+	.controls	  = es8328_snd_controls,
+	.num_controls	  = ARRAY_SIZE(es8328_snd_controls),
+	.dapm_widgets	  = es8328_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(es8328_dapm_widgets),
+	.dapm_routes	  = es8328_dapm_routes,
+	.num_dapm_routes  = ARRAY_SIZE(es8328_dapm_routes),
+};
+
+int es8328_probe(struct device *dev, struct regmap *regmap)
+{
+	struct es8328_priv *es8328;
+	int ret;
+	int i;
+
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	es8328 = devm_kzalloc(dev, sizeof(*es8328), GFP_KERNEL);
+	if (es8328 == NULL)
+		return -ENOMEM;
+
+	es8328->regmap = regmap;
+
+	for (i = 0; i < ARRAY_SIZE(es8328->supplies); i++)
+		es8328->supplies[i].supply = supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(es8328->supplies),
+				es8328->supplies);
+	if (ret) {
+		dev_err(dev, "unable to get regulators\n");
+		return ret;
+	}
+
+	dev_set_drvdata(dev, es8328);
+
+	return snd_soc_register_codec(dev,
+			&es8328_codec_driver, &es8328_dai, 1);
+}
+EXPORT_SYMBOL_GPL(es8328_probe);
+
+MODULE_DESCRIPTION("ASoC ES8328 driver");
+MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8328.h b/sound/soc/codecs/es8328.h
new file mode 100644
index 0000000..cb36afe
--- /dev/null
+++ b/sound/soc/codecs/es8328.h
@@ -0,0 +1,314 @@
+/*
+ * es8328.h  --  ES8328 ALSA SoC Audio driver
+ */
+
+#ifndef _ES8328_H
+#define _ES8328_H
+
+#include <linux/regmap.h>
+
+struct device;
+
+extern const struct regmap_config es8328_regmap_config;
+int es8328_probe(struct device *dev, struct regmap *regmap);
+
+#define ES8328_DACLVOL 46
+#define ES8328_DACRVOL 47
+#define ES8328_DACCTL 28
+#define ES8328_RATEMASK (0x1f << 0)
+
+#define ES8328_CONTROL1		0x00
+#define ES8328_CONTROL1_VMIDSEL_OFF (0 << 0)
+#define ES8328_CONTROL1_VMIDSEL_50k (1 << 0)
+#define ES8328_CONTROL1_VMIDSEL_500k (2 << 0)
+#define ES8328_CONTROL1_VMIDSEL_5k (3 << 0)
+#define ES8328_CONTROL1_VMIDSEL_MASK (7 << 0)
+#define ES8328_CONTROL1_ENREF (1 << 2)
+#define ES8328_CONTROL1_SEQEN (1 << 3)
+#define ES8328_CONTROL1_SAMEFS (1 << 4)
+#define ES8328_CONTROL1_DACMCLK_ADC (0 << 5)
+#define ES8328_CONTROL1_DACMCLK_DAC (1 << 5)
+#define ES8328_CONTROL1_LRCM (1 << 6)
+#define ES8328_CONTROL1_SCP_RESET (1 << 7)
+
+#define ES8328_CONTROL2		0x01
+#define ES8328_CONTROL2_VREF_BUF_OFF (1 << 0)
+#define ES8328_CONTROL2_VREF_LOWPOWER (1 << 1)
+#define ES8328_CONTROL2_IBIASGEN_OFF (1 << 2)
+#define ES8328_CONTROL2_ANALOG_OFF (1 << 3)
+#define ES8328_CONTROL2_VREF_BUF_LOWPOWER (1 << 4)
+#define ES8328_CONTROL2_VCM_MOD_LOWPOWER (1 << 5)
+#define ES8328_CONTROL2_OVERCURRENT_ON (1 << 6)
+#define ES8328_CONTROL2_THERMAL_SHUTDOWN_ON (1 << 7)
+
+#define ES8328_CHIPPOWER	0x02
+#define ES8328_CHIPPOWER_DACVREF_OFF 0
+#define ES8328_CHIPPOWER_ADCVREF_OFF 1
+#define ES8328_CHIPPOWER_DACDLL_OFF 2
+#define ES8328_CHIPPOWER_ADCDLL_OFF 3
+#define ES8328_CHIPPOWER_DACSTM_RESET 4
+#define ES8328_CHIPPOWER_ADCSTM_RESET 5
+#define ES8328_CHIPPOWER_DACDIG_OFF 6
+#define ES8328_CHIPPOWER_ADCDIG_OFF 7
+
+#define ES8328_ADCPOWER		0x03
+#define ES8328_ADCPOWER_INT1_LOWPOWER 0
+#define ES8328_ADCPOWER_FLASH_ADC_LOWPOWER 1
+#define ES8328_ADCPOWER_ADC_BIAS_GEN_OFF 2
+#define ES8328_ADCPOWER_MIC_BIAS_OFF 3
+#define ES8328_ADCPOWER_ADCR_OFF 4
+#define ES8328_ADCPOWER_ADCL_OFF 5
+#define ES8328_ADCPOWER_AINR_OFF 6
+#define ES8328_ADCPOWER_AINL_OFF 7
+
+#define ES8328_DACPOWER		0x04
+#define ES8328_DACPOWER_OUT3_ON 0
+#define ES8328_DACPOWER_MONO_ON 1
+#define ES8328_DACPOWER_ROUT2_ON 2
+#define ES8328_DACPOWER_LOUT2_ON 3
+#define ES8328_DACPOWER_ROUT1_ON 4
+#define ES8328_DACPOWER_LOUT1_ON 5
+#define ES8328_DACPOWER_RDAC_OFF 6
+#define ES8328_DACPOWER_LDAC_OFF 7
+
+#define ES8328_CHIPLOPOW1	0x05
+#define ES8328_CHIPLOPOW2	0x06
+#define ES8328_ANAVOLMANAG	0x07
+
+#define ES8328_MASTERMODE	0x08
+#define ES8328_MASTERMODE_BCLKDIV (0 << 0)
+#define ES8328_MASTERMODE_BCLK_INV (1 << 5)
+#define ES8328_MASTERMODE_MCLKDIV2 (1 << 6)
+#define ES8328_MASTERMODE_MSC (1 << 7)
+
+#define ES8328_ADCCONTROL1	0x09
+#define ES8328_ADCCONTROL2	0x0a
+#define ES8328_ADCCONTROL3	0x0b
+#define ES8328_ADCCONTROL4	0x0c
+#define ES8328_ADCCONTROL5	0x0d
+#define ES8328_ADCCONTROL5_RATEMASK (0x1f << 0)
+
+#define ES8328_ADCCONTROL6	0x0e
+
+#define ES8328_ADCCONTROL7	0x0f
+#define ES8328_ADCCONTROL7_ADC_MUTE (1 << 2)
+#define ES8328_ADCCONTROL7_ADC_LER (1 << 3)
+#define ES8328_ADCCONTROL7_ADC_ZERO_CROSS (1 << 4)
+#define ES8328_ADCCONTROL7_ADC_SOFT_RAMP (1 << 5)
+#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_4 (0 << 6)
+#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_8 (1 << 6)
+#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_16 (2 << 6)
+#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_32 (3 << 6)
+
+#define ES8328_ADCCONTROL8	0x10
+#define ES8328_ADCCONTROL9	0x11
+#define ES8328_ADCCONTROL10	0x12
+#define ES8328_ADCCONTROL11	0x13
+#define ES8328_ADCCONTROL12	0x14
+#define ES8328_ADCCONTROL13	0x15
+#define ES8328_ADCCONTROL14	0x16
+
+#define ES8328_DACCONTROL1	0x17
+#define ES8328_DACCONTROL1_DACFORMAT_I2S (0 << 1)
+#define ES8328_DACCONTROL1_DACFORMAT_LJUST (1 << 1)
+#define ES8328_DACCONTROL1_DACFORMAT_RJUST (2 << 1)
+#define ES8328_DACCONTROL1_DACFORMAT_PCM (3 << 1)
+#define ES8328_DACCONTROL1_DACWL_24 (0 << 3)
+#define ES8328_DACCONTROL1_DACWL_20 (1 << 3)
+#define ES8328_DACCONTROL1_DACWL_18 (2 << 3)
+#define ES8328_DACCONTROL1_DACWL_16 (3 << 3)
+#define ES8328_DACCONTROL1_DACWL_32 (4 << 3)
+#define ES8328_DACCONTROL1_DACLRP_I2S_POL_NORMAL (0 << 6)
+#define ES8328_DACCONTROL1_DACLRP_I2S_POL_INV (1 << 6)
+#define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK2 (0 << 6)
+#define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK1 (1 << 6)
+#define ES8328_DACCONTROL1_LRSWAP (1 << 7)
+
+#define ES8328_DACCONTROL2	0x18
+#define ES8328_DACCONTROL2_RATEMASK (0x1f << 0)
+#define ES8328_DACCONTROL2_DOUBLESPEED (1 << 5)
+
+#define ES8328_DACCONTROL3	0x19
+#define ES8328_DACCONTROL3_AUTOMUTE (1 << 2)
+#define ES8328_DACCONTROL3_DACMUTE (1 << 2)
+#define ES8328_DACCONTROL3_LEFTGAINVOL (1 << 3)
+#define ES8328_DACCONTROL3_DACZEROCROSS (1 << 4)
+#define ES8328_DACCONTROL3_DACSOFTRAMP (1 << 5)
+#define ES8328_DACCONTROL3_DACRAMPRATE (3 << 6)
+
+#define ES8328_LDACVOL 0x1a
+#define ES8328_LDACVOL_MASK (0 << 0)
+#define ES8328_LDACVOL_MAX (0xc0)
+
+#define ES8328_RDACVOL 0x1b
+#define ES8328_RDACVOL_MASK (0 << 0)
+#define ES8328_RDACVOL_MAX (0xc0)
+
+#define ES8328_DACVOL_MAX (0xc0)
+
+#define ES8328_DACCONTROL4	0x1a
+#define ES8328_DACCONTROL5	0x1b
+
+#define ES8328_DACCONTROL6	0x1c
+#define ES8328_DACCONTROL6_CLICKFREE (1 << 3)
+#define ES8328_DACCONTROL6_DAC_INVR (1 << 4)
+#define ES8328_DACCONTROL6_DAC_INVL (1 << 5)
+#define ES8328_DACCONTROL6_DEEMPH_OFF (0 << 6)
+#define ES8328_DACCONTROL6_DEEMPH_32k (1 << 6)
+#define ES8328_DACCONTROL6_DEEMPH_44_1k (2 << 6)
+#define ES8328_DACCONTROL6_DEEMPH_48k (3 << 6)
+
+#define ES8328_DACCONTROL7	0x1d
+#define ES8328_DACCONTROL7_VPP_SCALE_3p5	(0 << 0)
+#define ES8328_DACCONTROL7_VPP_SCALE_4p0	(1 << 0)
+#define ES8328_DACCONTROL7_VPP_SCALE_3p0	(2 << 0)
+#define ES8328_DACCONTROL7_VPP_SCALE_2p5	(3 << 0)
+#define ES8328_DACCONTROL7_SHELVING_STRENGTH (1 << 2) /* In eights */
+#define ES8328_DACCONTROL7_MONO		(1 << 5)
+#define ES8328_DACCONTROL7_ZEROR	(1 << 6)
+#define ES8328_DACCONTROL7_ZEROL	(1 << 7)
+
+/* Shelving filter */
+#define ES8328_DACCONTROL8	0x1e
+#define ES8328_DACCONTROL9	0x1f
+#define ES8328_DACCONTROL10	0x20
+#define ES8328_DACCONTROL11	0x21
+#define ES8328_DACCONTROL12	0x22
+#define ES8328_DACCONTROL13	0x23
+#define ES8328_DACCONTROL14	0x24
+#define ES8328_DACCONTROL15	0x25
+
+#define ES8328_DACCONTROL16	0x26
+#define ES8328_DACCONTROL16_RMIXSEL_RIN1 (0 << 0)
+#define ES8328_DACCONTROL16_RMIXSEL_RIN2 (1 << 0)
+#define ES8328_DACCONTROL16_RMIXSEL_RIN3 (2 << 0)
+#define ES8328_DACCONTROL16_RMIXSEL_RADC (3 << 0)
+#define ES8328_DACCONTROL16_LMIXSEL_LIN1 (0 << 3)
+#define ES8328_DACCONTROL16_LMIXSEL_LIN2 (1 << 3)
+#define ES8328_DACCONTROL16_LMIXSEL_LIN3 (2 << 3)
+#define ES8328_DACCONTROL16_LMIXSEL_LADC (3 << 3)
+
+#define ES8328_DACCONTROL17	0x27
+#define ES8328_DACCONTROL17_LI2LOVOL (7 << 3)
+#define ES8328_DACCONTROL17_LI2LO (1 << 6)
+#define ES8328_DACCONTROL17_LD2LO (1 << 7)
+
+#define ES8328_DACCONTROL18	0x28
+#define ES8328_DACCONTROL18_RI2LOVOL (7 << 3)
+#define ES8328_DACCONTROL18_RI2LO (1 << 6)
+#define ES8328_DACCONTROL18_RD2LO (1 << 7)
+
+#define ES8328_DACCONTROL19	0x29
+#define ES8328_DACCONTROL19_LI2ROVOL (7 << 3)
+#define ES8328_DACCONTROL19_LI2RO (1 << 6)
+#define ES8328_DACCONTROL19_LD2RO (1 << 7)
+
+#define ES8328_DACCONTROL20	0x2a
+#define ES8328_DACCONTROL20_RI2ROVOL (7 << 3)
+#define ES8328_DACCONTROL20_RI2RO (1 << 6)
+#define ES8328_DACCONTROL20_RD2RO (1 << 7)
+
+#define ES8328_DACCONTROL21	0x2b
+#define ES8328_DACCONTROL21_LI2MOVOL (7 << 3)
+#define ES8328_DACCONTROL21_LI2MO (1 << 6)
+#define ES8328_DACCONTROL21_LD2MO (1 << 7)
+
+#define ES8328_DACCONTROL22	0x2c
+#define ES8328_DACCONTROL22_RI2MOVOL (7 << 3)
+#define ES8328_DACCONTROL22_RI2MO (1 << 6)
+#define ES8328_DACCONTROL22_RD2MO (1 << 7)
+
+#define ES8328_DACCONTROL23	0x2d
+#define ES8328_DACCONTROL23_MOUTINV		(1 << 1)
+#define ES8328_DACCONTROL23_HPSWPOL		(1 << 2)
+#define ES8328_DACCONTROL23_HPSWEN		(1 << 3)
+#define ES8328_DACCONTROL23_VROI_1p5k		(0 << 4)
+#define ES8328_DACCONTROL23_VROI_40k		(1 << 4)
+#define ES8328_DACCONTROL23_OUT3_VREF		(0 << 5)
+#define ES8328_DACCONTROL23_OUT3_ROUT1		(1 << 5)
+#define ES8328_DACCONTROL23_OUT3_MONOOUT	(2 << 5)
+#define ES8328_DACCONTROL23_OUT3_RIGHT_MIXER	(3 << 5)
+#define ES8328_DACCONTROL23_ROUT2INV		(1 << 7)
+
+/* LOUT1 Amplifier */
+#define ES8328_LOUT1VOL 0x2e
+#define ES8328_LOUT1VOL_MASK (0 << 5)
+#define ES8328_LOUT1VOL_MAX (0x24)
+
+/* ROUT1 Amplifier */
+#define ES8328_ROUT1VOL 0x2f
+#define ES8328_ROUT1VOL_MASK (0 << 5)
+#define ES8328_ROUT1VOL_MAX (0x24)
+
+#define ES8328_OUT1VOL_MAX (0x24)
+
+/* LOUT2 Amplifier */
+#define ES8328_LOUT2VOL 0x30
+#define ES8328_LOUT2VOL_MASK (0 << 5)
+#define ES8328_LOUT2VOL_MAX (0x24)
+
+/* ROUT2 Amplifier */
+#define ES8328_ROUT2VOL 0x31
+#define ES8328_ROUT2VOL_MASK (0 << 5)
+#define ES8328_ROUT2VOL_MAX (0x24)
+
+#define ES8328_OUT2VOL_MAX (0x24)
+
+/* Mono Out Amplifier */
+#define ES8328_MONOOUTVOL 0x32
+#define ES8328_MONOOUTVOL_MASK (0 << 5)
+#define ES8328_MONOOUTVOL_MAX (0x24)
+
+#define ES8328_DACCONTROL29	0x33
+#define ES8328_DACCONTROL30	0x34
+
+#define ES8328_SYSCLK		0
+
+#define ES8328_REG_MAX		0x35
+
+#define ES8328_PLL1		0
+#define ES8328_PLL2		1
+
+/* clock inputs */
+#define ES8328_MCLK		0
+#define ES8328_PCMCLK		1
+
+/* clock divider id's */
+#define ES8328_PCMDIV		0
+#define ES8328_BCLKDIV		1
+#define ES8328_VXCLKDIV		2
+
+/* PCM clock dividers */
+#define ES8328_PCM_DIV_1	(0 << 6)
+#define ES8328_PCM_DIV_3	(2 << 6)
+#define ES8328_PCM_DIV_5_5	(3 << 6)
+#define ES8328_PCM_DIV_2	(4 << 6)
+#define ES8328_PCM_DIV_4	(5 << 6)
+#define ES8328_PCM_DIV_6	(6 << 6)
+#define ES8328_PCM_DIV_8	(7 << 6)
+
+/* BCLK clock dividers */
+#define ES8328_BCLK_DIV_1	(0 << 7)
+#define ES8328_BCLK_DIV_2	(1 << 7)
+#define ES8328_BCLK_DIV_4	(2 << 7)
+#define ES8328_BCLK_DIV_8	(3 << 7)
+
+/* VXCLK clock dividers */
+#define ES8328_VXCLK_DIV_1	(0 << 6)
+#define ES8328_VXCLK_DIV_2	(1 << 6)
+#define ES8328_VXCLK_DIV_4	(2 << 6)
+#define ES8328_VXCLK_DIV_8	(3 << 6)
+#define ES8328_VXCLK_DIV_16	(4 << 6)
+
+#define ES8328_DAI_HIFI		0
+#define ES8328_DAI_VOICE	1
+
+#define ES8328_1536FS		1536
+#define ES8328_1024FS		1024
+#define ES8328_768FS		768
+#define ES8328_512FS		512
+#define ES8328_384FS		384
+#define ES8328_256FS		256
+#define ES8328_128FS		128
+
+#endif
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
index bcebd1a..df7c01c 100644
--- a/sound/soc/codecs/jz4740.c
+++ b/sound/soc/codecs/jz4740.c
@@ -293,41 +293,13 @@
 	regmap_update_bits(jz4740_codec->regmap, JZ4740_REG_CODEC_1,
 			JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
 
-	jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
 	return 0;
 }
 
-static int jz4740_codec_dev_remove(struct snd_soc_codec *codec)
-{
-	jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-	return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-
-static int jz4740_codec_suspend(struct snd_soc_codec *codec)
-{
-	return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF);
-}
-
-static int jz4740_codec_resume(struct snd_soc_codec *codec)
-{
-	return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-}
-
-#else
-#define jz4740_codec_suspend NULL
-#define jz4740_codec_resume NULL
-#endif
-
 static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = {
 	.probe = jz4740_codec_dev_probe,
-	.remove = jz4740_codec_dev_remove,
-	.suspend = jz4740_codec_suspend,
-	.resume = jz4740_codec_resume,
 	.set_bias_level = jz4740_codec_set_bias_level,
+	.suspend_bias_off = true,
 
 	.controls = jz4740_codec_controls,
 	.num_controls = ARRAY_SIZE(jz4740_codec_controls),
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
index 275b3f7..c1ae576 100644
--- a/sound/soc/codecs/lm49453.c
+++ b/sound/soc/codecs/lm49453.c
@@ -1395,18 +1395,6 @@
 	},
 };
 
-static int lm49453_suspend(struct snd_soc_codec *codec)
-{
-	lm49453_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	return 0;
-}
-
-static int lm49453_resume(struct snd_soc_codec *codec)
-{
-	lm49453_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-	return 0;
-}
-
 /* power down chip */
 static int lm49453_remove(struct snd_soc_codec *codec)
 {
@@ -1416,8 +1404,6 @@
 
 static struct snd_soc_codec_driver soc_codec_dev_lm49453 = {
 	.remove = lm49453_remove,
-	.suspend = lm49453_suspend,
-	.resume = lm49453_resume,
 	.set_bias_level = lm49453_set_bias_level,
 	.controls = lm49453_snd_controls,
 	.num_controls = ARRAY_SIZE(lm49453_snd_controls),
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index 4a063fa..d519294 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -1311,8 +1311,6 @@
 	{"MIC1 Input", NULL, "MIC1"},
 	{"MIC2 Input", NULL, "MIC2"},
 
-	{"DMICL", NULL, "DMICL_ENA"},
-	{"DMICR", NULL, "DMICR_ENA"},
 	{"DMICL", NULL, "AHPF"},
 	{"DMICR", NULL, "AHPF"},
 
@@ -1370,6 +1368,8 @@
 	{"DMIC Mux", "ADC", "ADCR"},
 	{"DMIC Mux", "DMIC", "DMICL"},
 	{"DMIC Mux", "DMIC", "DMICR"},
+	{"DMIC Mux", "DMIC", "DMICL_ENA"},
+	{"DMIC Mux", "DMIC", "DMICR_ENA"},
 
 	{"LBENL Mux", "Normal", "DMIC Mux"},
 	{"LBENL Mux", "Loopback", "LTENL Mux"},
@@ -1972,6 +1972,102 @@
 	return 0;
 }
 
+static int max98090_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if (!max98090->master && dai->active == 1)
+			queue_delayed_work(system_power_efficient_wq,
+					   &max98090->pll_det_enable_work,
+					   msecs_to_jiffies(10));
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if (!max98090->master && dai->active == 1)
+			schedule_work(&max98090->pll_det_disable_work);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static void max98090_pll_det_enable_work(struct work_struct *work)
+{
+	struct max98090_priv *max98090 =
+		container_of(work, struct max98090_priv,
+			     pll_det_enable_work.work);
+	struct snd_soc_codec *codec = max98090->codec;
+	unsigned int status, mask;
+
+	/*
+	 * Clear status register in order to clear possibly already occurred
+	 * PLL unlock. If PLL hasn't still locked, the status will be set
+	 * again and PLL unlock interrupt will occur.
+	 * Note this will clear all status bits
+	 */
+	regmap_read(max98090->regmap, M98090_REG_DEVICE_STATUS, &status);
+
+	/*
+	 * Queue jack work in case jack state has just changed but handler
+	 * hasn't run yet
+	 */
+	regmap_read(max98090->regmap, M98090_REG_INTERRUPT_S, &mask);
+	status &= mask;
+	if (status & M98090_JDET_MASK)
+		queue_delayed_work(system_power_efficient_wq,
+				   &max98090->jack_work,
+				   msecs_to_jiffies(100));
+
+	/* Enable PLL unlock interrupt */
+	snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S,
+			    M98090_IULK_MASK,
+			    1 << M98090_IULK_SHIFT);
+}
+
+static void max98090_pll_det_disable_work(struct work_struct *work)
+{
+	struct max98090_priv *max98090 =
+		container_of(work, struct max98090_priv, pll_det_disable_work);
+	struct snd_soc_codec *codec = max98090->codec;
+
+	cancel_delayed_work_sync(&max98090->pll_det_enable_work);
+
+	/* Disable PLL unlock interrupt */
+	snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S,
+			    M98090_IULK_MASK, 0);
+}
+
+static void max98090_pll_work(struct work_struct *work)
+{
+	struct max98090_priv *max98090 =
+		container_of(work, struct max98090_priv, pll_work);
+	struct snd_soc_codec *codec = max98090->codec;
+
+	if (!snd_soc_codec_is_active(codec))
+		return;
+
+	dev_info(codec->dev, "PLL unlocked\n");
+
+	/* Toggle shutdown OFF then ON */
+	snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN,
+			    M98090_SHDNN_MASK, 0);
+	msleep(10);
+	snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN,
+			    M98090_SHDNN_MASK, M98090_SHDNN_MASK);
+
+	/* Give PLL time to lock */
+	msleep(10);
+}
+
 static void max98090_jack_work(struct work_struct *work)
 {
 	struct max98090_priv *max98090 = container_of(work,
@@ -2063,12 +2159,16 @@
 
 static irqreturn_t max98090_interrupt(int irq, void *data)
 {
-	struct snd_soc_codec *codec = data;
-	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+	struct max98090_priv *max98090 = data;
+	struct snd_soc_codec *codec = max98090->codec;
 	int ret;
 	unsigned int mask;
 	unsigned int active;
 
+	/* Treat interrupt before codec is initialized as spurious */
+	if (codec == NULL)
+		return IRQ_NONE;
+
 	dev_dbg(codec->dev, "***** max98090_interrupt *****\n");
 
 	ret = regmap_read(max98090->regmap, M98090_REG_INTERRUPT_S, &mask);
@@ -2103,8 +2203,10 @@
 	if (active & M98090_SLD_MASK)
 		dev_dbg(codec->dev, "M98090_SLD_MASK\n");
 
-	if (active & M98090_ULK_MASK)
-		dev_err(codec->dev, "M98090_ULK_MASK\n");
+	if (active & M98090_ULK_MASK) {
+		dev_dbg(codec->dev, "M98090_ULK_MASK\n");
+		schedule_work(&max98090->pll_work);
+	}
 
 	if (active & M98090_JDET_MASK) {
 		dev_dbg(codec->dev, "M98090_JDET_MASK\n");
@@ -2177,6 +2279,7 @@
 	.set_tdm_slot = max98090_set_tdm_slot,
 	.hw_params = max98090_dai_hw_params,
 	.digital_mute = max98090_dai_digital_mute,
+	.trigger = max98090_dai_trigger,
 };
 
 static struct snd_soc_dai_driver max98090_dai[] = {
@@ -2230,7 +2333,6 @@
 	max98090->lin_state = 0;
 	max98090->pa1en = 0;
 	max98090->pa2en = 0;
-	max98090->extmic_mux = 0;
 
 	ret = snd_soc_read(codec, M98090_REG_REVISION_ID);
 	if (ret < 0) {
@@ -2258,22 +2360,16 @@
 	max98090->jack_state = M98090_JACK_STATE_NO_HEADSET;
 
 	INIT_DELAYED_WORK(&max98090->jack_work, max98090_jack_work);
+	INIT_DELAYED_WORK(&max98090->pll_det_enable_work,
+			  max98090_pll_det_enable_work);
+	INIT_WORK(&max98090->pll_det_disable_work,
+		  max98090_pll_det_disable_work);
+	INIT_WORK(&max98090->pll_work, max98090_pll_work);
 
 	/* Enable jack detection */
 	snd_soc_write(codec, M98090_REG_JACK_DETECT,
 		M98090_JDETEN_MASK | M98090_JDEB_25MS);
 
-	/* Register for interrupts */
-	dev_dbg(codec->dev, "irq = %d\n", max98090->irq);
-
-	ret = devm_request_threaded_irq(codec->dev, max98090->irq, NULL,
-		max98090_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-		"max98090_interrupt", codec);
-	if (ret < 0) {
-		dev_err(codec->dev, "request_irq failed: %d\n",
-			ret);
-	}
-
 	/*
 	 * Clear any old interrupts.
 	 * An old interrupt ocurring prior to installing the ISR
@@ -2310,6 +2406,10 @@
 	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
 
 	cancel_delayed_work_sync(&max98090->jack_work);
+	cancel_delayed_work_sync(&max98090->pll_det_enable_work);
+	cancel_work_sync(&max98090->pll_det_disable_work);
+	cancel_work_sync(&max98090->pll_work);
+	max98090->codec = NULL;
 
 	return 0;
 }
@@ -2362,7 +2462,6 @@
 	max98090->devtype = driver_data;
 	i2c_set_clientdata(i2c, max98090);
 	max98090->pdata = i2c->dev.platform_data;
-	max98090->irq = i2c->irq;
 
 	max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap);
 	if (IS_ERR(max98090->regmap)) {
@@ -2371,6 +2470,15 @@
 		goto err_enable;
 	}
 
+	ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
+		max98090_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+		"max98090_interrupt", max98090);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "request_irq failed: %d\n",
+			ret);
+		return ret;
+	}
+
 	ret = snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_max98090, max98090_dai,
 			ARRAY_SIZE(max98090_dai));
diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h
index cf1b606..a5f6bad 100644
--- a/sound/soc/codecs/max98090.h
+++ b/sound/soc/codecs/max98090.h
@@ -11,11 +11,6 @@
 #ifndef _MAX98090_H
 #define _MAX98090_H
 
-#include <linux/version.h>
-
-/* One can override the Linux version here with an explicit version number */
-#define M98090_LINUX_VERSION LINUX_VERSION_CODE
-
 /*
  * MAX98090 Register Definitions
  */
@@ -1502,9 +1497,6 @@
 #define M98090_REVID_WIDTH		8
 #define M98090_REVID_NUM		(1<<M98090_REVID_WIDTH)
 
-#define M98090_BYTE1(w) ((w >> 8) & 0xff)
-#define M98090_BYTE0(w) (w & 0xff)
-
 /* Silicon revision number */
 #define M98090_REVA			0x40
 #define M98091_REVA			0x50
@@ -1529,9 +1521,11 @@
 	unsigned int bclk;
 	unsigned int lrclk;
 	struct max98090_cdata dai[1];
-	int irq;
 	int jack_state;
 	struct delayed_work jack_work;
+	struct delayed_work pll_det_enable_work;
+	struct work_struct pll_det_disable_work;
+	struct work_struct pll_work;
 	struct snd_soc_jack *jack;
 	unsigned int dai_fmt;
 	int tdm_slots;
@@ -1539,7 +1533,6 @@
 	u8 lin_state;
 	unsigned int pa1en;
 	unsigned int pa2en;
-	unsigned int extmic_mux;
 	unsigned int sidetone;
 	bool master;
 };
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c
index 388f90a..71f775a 100644
--- a/sound/soc/codecs/mc13783.c
+++ b/sound/soc/codecs/mc13783.c
@@ -765,12 +765,18 @@
 			return -ENOSYS;
 
 		ret = of_property_read_u32(np, "adc-port", &priv->adc_ssi_port);
-		if (ret)
-			goto out;
+		if (ret) {
+			of_node_put(np);
+			return ret;
+		}
 
 		ret = of_property_read_u32(np, "dac-port", &priv->dac_ssi_port);
-		if (ret)
-			goto out;
+		if (ret) {
+			of_node_put(np);
+			return ret;
+		}
+
+		of_node_put(np);
 	}
 
 	dev_set_drvdata(&pdev->dev, priv);
@@ -783,8 +789,6 @@
 		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783,
 			mc13783_dai_async, ARRAY_SIZE(mc13783_dai_async));
 
-out:
-	of_node_put(np);
 	return ret;
 }
 
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
index e661e84..711f550 100644
--- a/sound/soc/codecs/ml26124.c
+++ b/sound/soc/codecs/ml26124.c
@@ -565,41 +565,19 @@
 	.symmetric_rates = 1,
 };
 
-#ifdef CONFIG_PM
-static int ml26124_suspend(struct snd_soc_codec *codec)
-{
-	ml26124_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-	return 0;
-}
-
-static int ml26124_resume(struct snd_soc_codec *codec)
-{
-	ml26124_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-	return 0;
-}
-#else
-#define ml26124_suspend NULL
-#define ml26124_resume NULL
-#endif
-
 static int ml26124_probe(struct snd_soc_codec *codec)
 {
 	/* Software Reset */
 	snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 1);
 	snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 0);
 
-	ml26124_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
 	return 0;
 }
 
 static struct snd_soc_codec_driver soc_codec_dev_ml26124 = {
 	.probe =	ml26124_probe,
-	.suspend =	ml26124_suspend,
-	.resume =	ml26124_resume,
 	.set_bias_level = ml26124_set_bias_level,
+	.suspend_bias_off = true,
 	.dapm_widgets = ml26124_dapm_widgets,
 	.num_dapm_widgets = ARRAY_SIZE(ml26124_dapm_widgets),
 	.dapm_routes = ml26124_intercon,
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index b86b426..4aa555c 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -269,6 +269,7 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
 static void rt286_index_sync(struct snd_soc_codec *codec)
 {
 	struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
@@ -279,6 +280,7 @@
 				  rt286->index_cache[i].def);
 	}
 }
+#endif
 
 static int rt286_support_power_controls[] = {
 	RT286_DAC_OUT1,
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index f1ec6e6..c3f2dec 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -1906,6 +1906,32 @@
 	return 0;
 }
 
+int rt5640_dmic_enable(struct snd_soc_codec *codec,
+		       bool dmic1_data_pin, bool dmic2_data_pin)
+{
+	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+	regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
+		RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL);
+
+	if (dmic1_data_pin) {
+		regmap_update_bits(rt5640->regmap, RT5640_DMIC,
+			RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3);
+		regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
+			RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA);
+	}
+
+	if (dmic2_data_pin) {
+		regmap_update_bits(rt5640->regmap, RT5640_DMIC,
+			RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4);
+		regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
+			RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5640_dmic_enable);
+
 static int rt5640_probe(struct snd_soc_codec *codec)
 {
 	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
@@ -1945,6 +1971,10 @@
 		return -ENODEV;
 	}
 
+	if (rt5640->pdata.dmic_en)
+		rt5640_dmic_enable(codec, rt5640->pdata.dmic1_data_pin,
+					  rt5640->pdata.dmic2_data_pin);
+
 	return 0;
 }
 
@@ -2195,25 +2225,6 @@
 		regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4,
 					RT5640_IN_DF2, RT5640_IN_DF2);
 
-	if (rt5640->pdata.dmic_en) {
-		regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
-			RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL);
-
-		if (rt5640->pdata.dmic1_data_pin) {
-			regmap_update_bits(rt5640->regmap, RT5640_DMIC,
-				RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3);
-			regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
-				RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA);
-		}
-
-		if (rt5640->pdata.dmic2_data_pin) {
-			regmap_update_bits(rt5640->regmap, RT5640_DMIC,
-				RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4);
-			regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
-				RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA);
-		}
-	}
-
 	rt5640->hp_mute = 1;
 
 	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640,
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h
index 58ebe96..3deb8ba 100644
--- a/sound/soc/codecs/rt5640.h
+++ b/sound/soc/codecs/rt5640.h
@@ -2097,4 +2097,7 @@
 	bool hp_mute;
 };
 
+int rt5640_dmic_enable(struct snd_soc_codec *codec,
+		       bool dmic1_data_pin, bool dmic2_data_pin);
+
 #endif
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index a7762d0..3fb83bf 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -17,6 +17,7 @@
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
+#include <linux/gpio.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -2103,6 +2104,77 @@
 	return 0;
 }
 
+static int rt5645_jack_detect(struct snd_soc_codec *codec,
+	struct snd_soc_jack *jack)
+{
+	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+	int gpio_state, jack_type = 0;
+	unsigned int val;
+
+	gpio_state = gpio_get_value(rt5645->pdata.hp_det_gpio);
+
+	dev_dbg(codec->dev, "gpio = %d(%d)\n", rt5645->pdata.hp_det_gpio,
+		gpio_state);
+
+	if ((rt5645->pdata.gpio_hp_det_active_high && gpio_state) ||
+		(!rt5645->pdata.gpio_hp_det_active_high && !gpio_state)) {
+		snd_soc_dapm_force_enable_pin(&codec->dapm, "micbias1");
+		snd_soc_dapm_force_enable_pin(&codec->dapm, "micbias2");
+		snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
+		snd_soc_dapm_force_enable_pin(&codec->dapm, "Mic Det Power");
+		snd_soc_dapm_sync(&codec->dapm);
+
+		snd_soc_write(codec, RT5645_IN1_CTRL1, 0x0006);
+		snd_soc_write(codec, RT5645_JD_CTRL3, 0x00b0);
+
+		snd_soc_update_bits(codec, RT5645_IN1_CTRL2,
+			RT5645_CBJ_MN_JD, 0);
+		snd_soc_update_bits(codec, RT5645_IN1_CTRL2,
+			RT5645_CBJ_MN_JD, RT5645_CBJ_MN_JD);
+
+		msleep(400);
+		val = snd_soc_read(codec, RT5645_IN1_CTRL3) & 0x7;
+		dev_dbg(codec->dev, "val = %d\n", val);
+
+		if (val == 1 || val == 2)
+			jack_type = SND_JACK_HEADSET;
+		else
+			jack_type = SND_JACK_HEADPHONE;
+
+		snd_soc_dapm_disable_pin(&codec->dapm, "micbias1");
+		snd_soc_dapm_disable_pin(&codec->dapm, "micbias2");
+		snd_soc_dapm_disable_pin(&codec->dapm, "LDO2");
+		snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power");
+		snd_soc_dapm_sync(&codec->dapm);
+	}
+
+	snd_soc_jack_report(rt5645->jack, jack_type, SND_JACK_HEADSET);
+
+	return 0;
+}
+
+int rt5645_set_jack_detect(struct snd_soc_codec *codec,
+	struct snd_soc_jack *jack)
+{
+	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+
+	rt5645->jack = jack;
+
+	rt5645_jack_detect(codec, rt5645->jack);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5645_set_jack_detect);
+
+static irqreturn_t rt5645_irq(int irq, void *data)
+{
+	struct rt5645_priv *rt5645 = data;
+
+	rt5645_jack_detect(rt5645->codec, rt5645->jack);
+
+	return IRQ_HANDLED;
+}
+
 static int rt5645_probe(struct snd_soc_codec *codec)
 {
 	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
@@ -2250,6 +2322,7 @@
 	if (rt5645 == NULL)
 		return -ENOMEM;
 
+	rt5645->i2c = i2c;
 	i2c_set_clientdata(i2c, rt5645);
 
 	if (pdata)
@@ -2345,12 +2418,38 @@
 
 	}
 
+	if (rt5645->i2c->irq) {
+		ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq,
+			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+			| IRQF_ONESHOT, "rt5645", rt5645);
+		if (ret)
+			dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+	}
+
+	if (gpio_is_valid(rt5645->pdata.hp_det_gpio)) {
+		ret = gpio_request(rt5645->pdata.hp_det_gpio, "rt5645");
+		if (ret)
+			dev_err(&i2c->dev, "Fail gpio_request hp_det_gpio\n");
+
+		ret = gpio_direction_input(rt5645->pdata.hp_det_gpio);
+		if (ret)
+			dev_err(&i2c->dev, "Fail gpio_direction hp_det_gpio\n");
+	}
+
 	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645,
 				      rt5645_dai, ARRAY_SIZE(rt5645_dai));
 }
 
 static int rt5645_i2c_remove(struct i2c_client *i2c)
 {
+	struct rt5645_priv *rt5645 = i2c_get_clientdata(i2c);
+
+	if (i2c->irq)
+		free_irq(i2c->irq, rt5645);
+
+	if (gpio_is_valid(rt5645->pdata.hp_det_gpio))
+		gpio_free(rt5645->pdata.hp_det_gpio);
+
 	snd_soc_unregister_codec(&i2c->dev);
 
 	return 0;
diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h
index 355b7e9..50c62c5 100644
--- a/sound/soc/codecs/rt5645.h
+++ b/sound/soc/codecs/rt5645.h
@@ -2166,6 +2166,8 @@
 	struct snd_soc_codec *codec;
 	struct rt5645_platform_data pdata;
 	struct regmap *regmap;
+	struct i2c_client *i2c;
+	struct snd_soc_jack *jack;
 
 	int sysclk;
 	int sysclk_src;
@@ -2178,4 +2180,7 @@
 	int pll_out;
 };
 
+int rt5645_set_jack_detect(struct snd_soc_codec *codec,
+	struct snd_soc_jack *jack);
+
 #endif /* __RT5645_H__ */
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index 5337c44..16aa4d9 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -15,10 +15,12 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
+#include <linux/of_gpio.h>
 #include <linux/regmap.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
+#include <linux/gpio.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -540,6 +542,7 @@
 static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
 static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
 static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+static const DECLARE_TLV_DB_SCALE(st_vol_tlv, -4650, 150, 0);
 
 /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
 static unsigned int bst_tlv[] = {
@@ -604,6 +607,10 @@
 		RT5677_MONO_ADC_L_VOL_SFT, RT5677_MONO_ADC_R_VOL_SFT, 127, 0,
 		adc_vol_tlv),
 
+	/* Sidetone Control */
+	SOC_SINGLE_TLV("Sidetone Volume", RT5677_SIDETONE_CTRL,
+		RT5677_ST_VOL_SFT, 31, 0, st_vol_tlv),
+
 	/* ADC Boost Volume Control */
 	SOC_DOUBLE_TLV("STO1 ADC Boost Volume", RT5677_STO1_2_ADC_BST,
 		RT5677_STO1_ADC_L_BST_SFT, RT5677_STO1_ADC_R_BST_SFT, 3, 0,
@@ -1700,14 +1707,19 @@
 
 	SND_SOC_DAPM_INPUT("Haptic Generator"),
 
-	SND_SOC_DAPM_PGA("DMIC1", RT5677_DMIC_CTRL1, RT5677_DMIC_1_EN_SFT, 0,
-		NULL, 0),
-	SND_SOC_DAPM_PGA("DMIC2", RT5677_DMIC_CTRL1, RT5677_DMIC_2_EN_SFT, 0,
-		NULL, 0),
-	SND_SOC_DAPM_PGA("DMIC3", RT5677_DMIC_CTRL1, RT5677_DMIC_3_EN_SFT, 0,
-		NULL, 0),
-	SND_SOC_DAPM_PGA("DMIC4", RT5677_DMIC_CTRL2, RT5677_DMIC_4_EN_SFT, 0,
-		NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC4", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("DMIC1 power", RT5677_DMIC_CTRL1,
+		RT5677_DMIC_1_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMIC2 power", RT5677_DMIC_CTRL1,
+		RT5677_DMIC_2_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMIC3 power", RT5677_DMIC_CTRL1,
+		RT5677_DMIC_3_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMIC4 power", RT5677_DMIC_CTRL2,
+		RT5677_DMIC_4_EN_SFT, 0, NULL, 0),
 
 	SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
 		set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
@@ -1987,6 +1999,9 @@
 	/* Sidetone Mux */
 	SND_SOC_DAPM_MUX("Sidetone Mux", SND_SOC_NOPM, 0, 0,
 			&rt5677_sidetone_mux),
+	SND_SOC_DAPM_SUPPLY("Sidetone Power", RT5677_SIDETONE_CTRL,
+		RT5677_ST_EN_SFT, 0, NULL, 0),
+
 	/* VAD Mux*/
 	SND_SOC_DAPM_MUX("VAD ADC Mux", SND_SOC_NOPM, 0, 0,
 			&rt5677_vad_src_mux),
@@ -2130,6 +2145,13 @@
 	{ "DMIC L4", NULL, "DMIC CLK" },
 	{ "DMIC R4", NULL, "DMIC CLK" },
 
+	{ "DMIC L1", NULL, "DMIC1 power" },
+	{ "DMIC R1", NULL, "DMIC1 power" },
+	{ "DMIC L3", NULL, "DMIC3 power" },
+	{ "DMIC R3", NULL, "DMIC3 power" },
+	{ "DMIC L4", NULL, "DMIC4 power" },
+	{ "DMIC R4", NULL, "DMIC4 power" },
+
 	{ "BST1", NULL, "IN1P" },
 	{ "BST1", NULL, "IN1N" },
 	{ "BST2", NULL, "IN2P" },
@@ -2691,6 +2713,7 @@
 	{ "Sidetone Mux", "DMIC4 L", "DMIC L4" },
 	{ "Sidetone Mux", "ADC1", "ADC 1" },
 	{ "Sidetone Mux", "ADC2", "ADC 2" },
+	{ "Sidetone Mux", NULL, "Sidetone Power" },
 
 	{ "Stereo DAC MIXL", "ST L Switch", "Sidetone Mux" },
 	{ "Stereo DAC MIXL", "DAC1 L Switch", "DAC1 MIXL" },
@@ -2793,6 +2816,16 @@
 	{ "PDM2R", NULL, "PDM2 R Mux" },
 };
 
+static const struct snd_soc_dapm_route rt5677_dmic2_clk_1[] = {
+	{ "DMIC L2", NULL, "DMIC1 power" },
+	{ "DMIC R2", NULL, "DMIC1 power" },
+};
+
+static const struct snd_soc_dapm_route rt5677_dmic2_clk_2[] = {
+	{ "DMIC L2", NULL, "DMIC2 power" },
+	{ "DMIC R2", NULL, "DMIC2 power" },
+};
+
 static int rt5677_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
@@ -3084,6 +3117,59 @@
 	return 0;
 }
 
+static int rt5677_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+			unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	unsigned int val = 0;
+
+	if (rx_mask || tx_mask)
+		val |= (1 << 12);
+
+	switch (slots) {
+	case 4:
+		val |= (1 << 10);
+		break;
+	case 6:
+		val |= (2 << 10);
+		break;
+	case 8:
+		val |= (3 << 10);
+		break;
+	case 2:
+	default:
+		break;
+	}
+
+	switch (slot_width) {
+	case 20:
+		val |= (1 << 8);
+		break;
+	case 24:
+		val |= (2 << 8);
+		break;
+	case 32:
+		val |= (3 << 8);
+		break;
+	case 16:
+	default:
+		break;
+	}
+
+	switch (dai->id) {
+	case RT5677_AIF1:
+		snd_soc_update_bits(codec, RT5677_TDM1_CTRL1, 0x1f00, val);
+		break;
+	case RT5677_AIF2:
+		snd_soc_update_bits(codec, RT5677_TDM2_CTRL1, 0x1f00, val);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
 static int rt5677_set_bias_level(struct snd_soc_codec *codec,
 			enum snd_soc_bias_level level)
 {
@@ -3138,12 +3224,148 @@
 	return 0;
 }
 
+#ifdef CONFIG_GPIOLIB
+static inline struct rt5677_priv *gpio_to_rt5677(struct gpio_chip *chip)
+{
+	return container_of(chip, struct rt5677_priv, gpio_chip);
+}
+
+static void rt5677_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
+
+	switch (offset) {
+	case RT5677_GPIO1 ... RT5677_GPIO5:
+		regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
+			0x1 << (offset * 3 + 1), !!value << (offset * 3 + 1));
+		break;
+
+	case RT5677_GPIO6:
+		regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3,
+			RT5677_GPIO6_OUT_MASK, !!value << RT5677_GPIO6_OUT_SFT);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int rt5677_gpio_direction_out(struct gpio_chip *chip,
+				     unsigned offset, int value)
+{
+	struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
+
+	switch (offset) {
+	case RT5677_GPIO1 ... RT5677_GPIO5:
+		regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
+			0x3 << (offset * 3 + 1),
+			(0x2 | !!value) << (offset * 3 + 1));
+		break;
+
+	case RT5677_GPIO6:
+		regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3,
+			RT5677_GPIO6_DIR_MASK | RT5677_GPIO6_OUT_MASK,
+			RT5677_GPIO6_DIR_OUT | !!value << RT5677_GPIO6_OUT_SFT);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5677_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
+	int value, ret;
+
+	ret = regmap_read(rt5677->regmap, RT5677_GPIO_ST, &value);
+	if (ret < 0)
+		return ret;
+
+	return (value & (0x1 << offset)) >> offset;
+}
+
+static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+	struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
+
+	switch (offset) {
+	case RT5677_GPIO1 ... RT5677_GPIO5:
+		regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
+			0x1 << (offset * 3 + 2), 0x0);
+		break;
+
+	case RT5677_GPIO6:
+		regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3,
+			RT5677_GPIO6_DIR_MASK, RT5677_GPIO6_DIR_IN);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static struct gpio_chip rt5677_template_chip = {
+	.label			= "rt5677",
+	.owner			= THIS_MODULE,
+	.direction_output	= rt5677_gpio_direction_out,
+	.set			= rt5677_gpio_set,
+	.direction_input	= rt5677_gpio_direction_in,
+	.get			= rt5677_gpio_get,
+	.can_sleep		= 1,
+};
+
+static void rt5677_init_gpio(struct i2c_client *i2c)
+{
+	struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c);
+	int ret;
+
+	rt5677->gpio_chip = rt5677_template_chip;
+	rt5677->gpio_chip.ngpio = RT5677_GPIO_NUM;
+	rt5677->gpio_chip.dev = &i2c->dev;
+	rt5677->gpio_chip.base = -1;
+
+	ret = gpiochip_add(&rt5677->gpio_chip);
+	if (ret != 0)
+		dev_err(&i2c->dev, "Failed to add GPIOs: %d\n", ret);
+}
+
+static void rt5677_free_gpio(struct i2c_client *i2c)
+{
+	struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c);
+
+	gpiochip_remove(&rt5677->gpio_chip);
+}
+#else
+static void rt5677_init_gpio(struct i2c_client *i2c)
+{
+}
+
+static void rt5677_free_gpio(struct i2c_client *i2c)
+{
+}
+#endif
+
 static int rt5677_probe(struct snd_soc_codec *codec)
 {
 	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
 	rt5677->codec = codec;
 
+	if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) {
+		snd_soc_dapm_add_routes(&codec->dapm,
+			rt5677_dmic2_clk_2,
+			ARRAY_SIZE(rt5677_dmic2_clk_2));
+	} else { /*use dmic1 clock by default*/
+		snd_soc_dapm_add_routes(&codec->dapm,
+			rt5677_dmic2_clk_1,
+			ARRAY_SIZE(rt5677_dmic2_clk_1));
+	}
+
 	rt5677_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
 	regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020);
@@ -3157,6 +3379,8 @@
 	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
 	regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec);
+	if (gpio_is_valid(rt5677->pow_ldo2))
+		gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
 
 	return 0;
 }
@@ -3168,6 +3392,8 @@
 
 	regcache_cache_only(rt5677->regmap, true);
 	regcache_mark_dirty(rt5677->regmap);
+	if (gpio_is_valid(rt5677->pow_ldo2))
+		gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
 
 	return 0;
 }
@@ -3176,6 +3402,10 @@
 {
 	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
+	if (gpio_is_valid(rt5677->pow_ldo2)) {
+		gpio_set_value_cansleep(rt5677->pow_ldo2, 1);
+		msleep(10);
+	}
 	regcache_cache_only(rt5677->regmap, false);
 	regcache_sync(rt5677->regmap);
 
@@ -3195,6 +3425,7 @@
 	.set_fmt = rt5677_set_dai_fmt,
 	.set_sysclk = rt5677_set_dai_sysclk,
 	.set_pll = rt5677_set_dai_pll,
+	.set_tdm_slot = rt5677_set_tdm_slot,
 };
 
 static struct snd_soc_dai_driver rt5677_dai[] = {
@@ -3333,6 +3564,35 @@
 };
 MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id);
 
+static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np)
+{
+	rt5677->pdata.in1_diff = of_property_read_bool(np,
+					"realtek,in1-differential");
+	rt5677->pdata.in2_diff = of_property_read_bool(np,
+					"realtek,in2-differential");
+	rt5677->pdata.lout1_diff = of_property_read_bool(np,
+					"realtek,lout1-differential");
+	rt5677->pdata.lout2_diff = of_property_read_bool(np,
+					"realtek,lout2-differential");
+	rt5677->pdata.lout3_diff = of_property_read_bool(np,
+					"realtek,lout3-differential");
+
+	rt5677->pow_ldo2 = of_get_named_gpio(np,
+					"realtek,pow-ldo2-gpio", 0);
+
+	/*
+	 * POW_LDO2 is optional (it may be statically tied on the board).
+	 * -ENOENT means that the property doesn't exist, i.e. there is no
+	 * GPIO, so is not an error. Any other error code means the property
+	 * exists, but could not be parsed.
+	 */
+	if (!gpio_is_valid(rt5677->pow_ldo2) &&
+			(rt5677->pow_ldo2 != -ENOENT))
+		return rt5677->pow_ldo2;
+
+	return 0;
+}
+
 static int rt5677_i2c_probe(struct i2c_client *i2c,
 		    const struct i2c_device_id *id)
 {
@@ -3351,6 +3611,33 @@
 	if (pdata)
 		rt5677->pdata = *pdata;
 
+	if (i2c->dev.of_node) {
+		ret = rt5677_parse_dt(rt5677, i2c->dev.of_node);
+		if (ret) {
+			dev_err(&i2c->dev, "Failed to parse device tree: %d\n",
+				ret);
+			return ret;
+		}
+	} else {
+		rt5677->pow_ldo2 = -EINVAL;
+	}
+
+	if (gpio_is_valid(rt5677->pow_ldo2)) {
+		ret = devm_gpio_request_one(&i2c->dev, rt5677->pow_ldo2,
+					    GPIOF_OUT_INIT_HIGH,
+					    "RT5677 POW_LDO2");
+		if (ret < 0) {
+			dev_err(&i2c->dev, "Failed to request POW_LDO2 %d: %d\n",
+				rt5677->pow_ldo2, ret);
+			return ret;
+		}
+		/* Wait a while until I2C bus becomes available. The datasheet
+		 * does not specify the exact we should wait but startup
+		 * sequence mentiones at least a few milliseconds.
+		 */
+		msleep(10);
+	}
+
 	rt5677->regmap = devm_regmap_init_i2c(i2c, &rt5677_regmap);
 	if (IS_ERR(rt5677->regmap)) {
 		ret = PTR_ERR(rt5677->regmap);
@@ -3381,6 +3668,29 @@
 		regmap_update_bits(rt5677->regmap, RT5677_IN1,
 					RT5677_IN_DF2, RT5677_IN_DF2);
 
+	if (rt5677->pdata.lout1_diff)
+		regmap_update_bits(rt5677->regmap, RT5677_LOUT1,
+					RT5677_LOUT1_L_DF, RT5677_LOUT1_L_DF);
+
+	if (rt5677->pdata.lout2_diff)
+		regmap_update_bits(rt5677->regmap, RT5677_LOUT1,
+					RT5677_LOUT2_L_DF, RT5677_LOUT2_L_DF);
+
+	if (rt5677->pdata.lout3_diff)
+		regmap_update_bits(rt5677->regmap, RT5677_LOUT1,
+					RT5677_LOUT3_L_DF, RT5677_LOUT3_L_DF);
+
+	if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) {
+		regmap_update_bits(rt5677->regmap, RT5677_GEN_CTRL2,
+					RT5677_GPIO5_FUNC_MASK,
+					RT5677_GPIO5_FUNC_DMIC);
+		regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
+					RT5677_GPIO5_DIR_MASK,
+					RT5677_GPIO5_DIR_OUT);
+	}
+
+	rt5677_init_gpio(i2c);
+
 	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677,
 				      rt5677_dai, ARRAY_SIZE(rt5677_dai));
 }
@@ -3388,6 +3698,7 @@
 static int rt5677_i2c_remove(struct i2c_client *i2c)
 {
 	snd_soc_unregister_codec(&i2c->dev);
+	rt5677_free_gpio(i2c);
 
 	return 0;
 }
diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h
index 863393e..d4eb6d5 100644
--- a/sound/soc/codecs/rt5677.h
+++ b/sound/soc/codecs/rt5677.h
@@ -382,6 +382,10 @@
 #define RT5677_ST_SEL_SFT			9
 #define RT5677_ST_EN				(0x1 << 6)
 #define RT5677_ST_EN_SFT			6
+#define RT5677_ST_GAIN				(0x1 << 5)
+#define RT5677_ST_GAIN_SFT			5
+#define RT5677_ST_VOL_MASK			(0x1f << 0)
+#define RT5677_ST_VOL_SFT			0
 
 /* Analog DAC1/2/3 Source Control (0x15) */
 #define RT5677_ANA_DAC3_SRC_SEL_MASK		(0x3 << 4)
@@ -1287,16 +1291,16 @@
 #define RT5677_PLL1_PD_SFT			8
 #define RT5677_PLL1_PD_1			(0x0 << 8)
 #define RT5677_PLL1_PD_2			(0x1 << 8)
-#define RT5671_DAC_OSR_MASK			(0x3 << 6)
-#define RT5671_DAC_OSR_SFT			6
-#define RT5671_DAC_OSR_128			(0x0 << 6)
-#define RT5671_DAC_OSR_64			(0x1 << 6)
-#define RT5671_DAC_OSR_32			(0x2 << 6)
-#define RT5671_ADC_OSR_MASK			(0x3 << 4)
-#define RT5671_ADC_OSR_SFT			4
-#define RT5671_ADC_OSR_128			(0x0 << 4)
-#define RT5671_ADC_OSR_64			(0x1 << 4)
-#define RT5671_ADC_OSR_32			(0x2 << 4)
+#define RT5677_DAC_OSR_MASK			(0x3 << 6)
+#define RT5677_DAC_OSR_SFT			6
+#define RT5677_DAC_OSR_128			(0x0 << 6)
+#define RT5677_DAC_OSR_64			(0x1 << 6)
+#define RT5677_DAC_OSR_32			(0x2 << 6)
+#define RT5677_ADC_OSR_MASK			(0x3 << 4)
+#define RT5677_ADC_OSR_SFT			4
+#define RT5677_ADC_OSR_128			(0x0 << 4)
+#define RT5677_ADC_OSR_64			(0x1 << 4)
+#define RT5677_ADC_OSR_32			(0x2 << 4)
 
 /* Global Clock Control 2 (0x81) */
 #define RT5677_PLL2_PR_SRC_MASK			(0x1 << 15)
@@ -1312,18 +1316,18 @@
 #define RT5677_PLL2_SRC_BCLK4			(0x4 << 12)
 #define RT5677_PLL2_SRC_RCCLK			(0x5 << 12)
 #define RT5677_PLL2_SRC_SLIM			(0x6 << 12)
-#define RT5671_DSP_ASRC_O_SRC			(0x3 << 10)
-#define RT5671_DSP_ASRC_O_SRC_SFT		10
-#define RT5671_DSP_ASRC_O_MCLK			(0x0 << 10)
-#define RT5671_DSP_ASRC_O_PLL1			(0x1 << 10)
-#define RT5671_DSP_ASRC_O_SLIM			(0x2 << 10)
-#define RT5671_DSP_ASRC_O_RCCLK			(0x3 << 10)
-#define RT5671_DSP_ASRC_I_SRC			(0x3 << 8)
-#define RT5671_DSP_ASRC_I_SRC_SFT		8
-#define RT5671_DSP_ASRC_I_MCLK			(0x0 << 8)
-#define RT5671_DSP_ASRC_I_PLL1			(0x1 << 8)
-#define RT5671_DSP_ASRC_I_SLIM			(0x2 << 8)
-#define RT5671_DSP_ASRC_I_RCCLK			(0x3 << 8)
+#define RT5677_DSP_ASRC_O_SRC			(0x3 << 10)
+#define RT5677_DSP_ASRC_O_SRC_SFT		10
+#define RT5677_DSP_ASRC_O_MCLK			(0x0 << 10)
+#define RT5677_DSP_ASRC_O_PLL1			(0x1 << 10)
+#define RT5677_DSP_ASRC_O_SLIM			(0x2 << 10)
+#define RT5677_DSP_ASRC_O_RCCLK			(0x3 << 10)
+#define RT5677_DSP_ASRC_I_SRC			(0x3 << 8)
+#define RT5677_DSP_ASRC_I_SRC_SFT		8
+#define RT5677_DSP_ASRC_I_MCLK			(0x0 << 8)
+#define RT5677_DSP_ASRC_I_PLL1			(0x1 << 8)
+#define RT5677_DSP_ASRC_I_SLIM			(0x2 << 8)
+#define RT5677_DSP_ASRC_I_RCCLK			(0x3 << 8)
 #define RT5677_DSP_CLK_SRC_MASK			(0x1 << 7)
 #define RT5677_DSP_CLK_SRC_SFT			7
 #define RT5677_DSP_CLK_SRC_PLL2			(0x0 << 7)
@@ -1363,6 +1367,110 @@
 #define RT5677_SEL_SRC_IB01			(0x1 << 0)
 #define RT5677_SEL_SRC_IB01_SFT			0
 
+/* GPIO status (0xbf) */
+#define RT5677_GPIO6_STATUS_MASK		(0x1 << 5)
+#define RT5677_GPIO6_STATUS_SFT			5
+#define RT5677_GPIO5_STATUS_MASK		(0x1 << 4)
+#define RT5677_GPIO5_STATUS_SFT			4
+#define RT5677_GPIO4_STATUS_MASK		(0x1 << 3)
+#define RT5677_GPIO4_STATUS_SFT			3
+#define RT5677_GPIO3_STATUS_MASK		(0x1 << 2)
+#define RT5677_GPIO3_STATUS_SFT			2
+#define RT5677_GPIO2_STATUS_MASK		(0x1 << 1)
+#define RT5677_GPIO2_STATUS_SFT			1
+#define RT5677_GPIO1_STATUS_MASK		(0x1 << 0)
+#define RT5677_GPIO1_STATUS_SFT			0
+
+/* GPIO Control 1 (0xc0) */
+#define RT5677_GPIO1_PIN_MASK			(0x1 << 15)
+#define RT5677_GPIO1_PIN_SFT			15
+#define RT5677_GPIO1_PIN_GPIO1			(0x0 << 15)
+#define RT5677_GPIO1_PIN_IRQ			(0x1 << 15)
+#define RT5677_IPTV_MODE_MASK			(0x1 << 14)
+#define RT5677_IPTV_MODE_SFT			14
+#define RT5677_IPTV_MODE_GPIO			(0x0 << 14)
+#define RT5677_IPTV_MODE_IPTV			(0x1 << 14)
+#define RT5677_FUNC_MODE_MASK			(0x1 << 13)
+#define RT5677_FUNC_MODE_SFT			13
+#define RT5677_FUNC_MODE_DMIC_GPIO		(0x0 << 13)
+#define RT5677_FUNC_MODE_JTAG			(0x1 << 13)
+
+/* GPIO Control 2 (0xc1) */
+#define RT5677_GPIO5_DIR_MASK			(0x1 << 14)
+#define RT5677_GPIO5_DIR_SFT			14
+#define RT5677_GPIO5_DIR_IN			(0x0 << 14)
+#define RT5677_GPIO5_DIR_OUT			(0x1 << 14)
+#define RT5677_GPIO5_OUT_MASK			(0x1 << 13)
+#define RT5677_GPIO5_OUT_SFT			13
+#define RT5677_GPIO5_OUT_LO			(0x0 << 13)
+#define RT5677_GPIO5_OUT_HI			(0x1 << 13)
+#define RT5677_GPIO5_P_MASK			(0x1 << 12)
+#define RT5677_GPIO5_P_SFT			12
+#define RT5677_GPIO5_P_NOR			(0x0 << 12)
+#define RT5677_GPIO5_P_INV			(0x1 << 12)
+#define RT5677_GPIO4_DIR_MASK			(0x1 << 11)
+#define RT5677_GPIO4_DIR_SFT			11
+#define RT5677_GPIO4_DIR_IN			(0x0 << 11)
+#define RT5677_GPIO4_DIR_OUT			(0x1 << 11)
+#define RT5677_GPIO4_OUT_MASK			(0x1 << 10)
+#define RT5677_GPIO4_OUT_SFT			10
+#define RT5677_GPIO4_OUT_LO			(0x0 << 10)
+#define RT5677_GPIO4_OUT_HI			(0x1 << 10)
+#define RT5677_GPIO4_P_MASK			(0x1 << 9)
+#define RT5677_GPIO4_P_SFT			9
+#define RT5677_GPIO4_P_NOR			(0x0 << 9)
+#define RT5677_GPIO4_P_INV			(0x1 << 9)
+#define RT5677_GPIO3_DIR_MASK			(0x1 << 8)
+#define RT5677_GPIO3_DIR_SFT			8
+#define RT5677_GPIO3_DIR_IN			(0x0 << 8)
+#define RT5677_GPIO3_DIR_OUT			(0x1 << 8)
+#define RT5677_GPIO3_OUT_MASK			(0x1 << 7)
+#define RT5677_GPIO3_OUT_SFT			7
+#define RT5677_GPIO3_OUT_LO			(0x0 << 7)
+#define RT5677_GPIO3_OUT_HI			(0x1 << 7)
+#define RT5677_GPIO3_P_MASK			(0x1 << 6)
+#define RT5677_GPIO3_P_SFT			6
+#define RT5677_GPIO3_P_NOR			(0x0 << 6)
+#define RT5677_GPIO3_P_INV			(0x1 << 6)
+#define RT5677_GPIO2_DIR_MASK			(0x1 << 5)
+#define RT5677_GPIO2_DIR_SFT			5
+#define RT5677_GPIO2_DIR_IN			(0x0 << 5)
+#define RT5677_GPIO2_DIR_OUT			(0x1 << 5)
+#define RT5677_GPIO2_OUT_MASK			(0x1 << 4)
+#define RT5677_GPIO2_OUT_SFT			4
+#define RT5677_GPIO2_OUT_LO			(0x0 << 4)
+#define RT5677_GPIO2_OUT_HI			(0x1 << 4)
+#define RT5677_GPIO2_P_MASK			(0x1 << 3)
+#define RT5677_GPIO2_P_SFT			3
+#define RT5677_GPIO2_P_NOR			(0x0 << 3)
+#define RT5677_GPIO2_P_INV			(0x1 << 3)
+#define RT5677_GPIO1_DIR_MASK			(0x1 << 2)
+#define RT5677_GPIO1_DIR_SFT			2
+#define RT5677_GPIO1_DIR_IN			(0x0 << 2)
+#define RT5677_GPIO1_DIR_OUT			(0x1 << 2)
+#define RT5677_GPIO1_OUT_MASK			(0x1 << 1)
+#define RT5677_GPIO1_OUT_SFT			1
+#define RT5677_GPIO1_OUT_LO			(0x0 << 1)
+#define RT5677_GPIO1_OUT_HI			(0x1 << 1)
+#define RT5677_GPIO1_P_MASK			(0x1 << 0)
+#define RT5677_GPIO1_P_SFT			0
+#define RT5677_GPIO1_P_NOR			(0x0 << 0)
+#define RT5677_GPIO1_P_INV			(0x1 << 0)
+
+/* GPIO Control 3 (0xc2) */
+#define RT5677_GPIO6_DIR_MASK			(0x1 << 2)
+#define RT5677_GPIO6_DIR_SFT			2
+#define RT5677_GPIO6_DIR_IN			(0x0 << 2)
+#define RT5677_GPIO6_DIR_OUT			(0x1 << 2)
+#define RT5677_GPIO6_OUT_MASK			(0x1 << 1)
+#define RT5677_GPIO6_OUT_SFT			1
+#define RT5677_GPIO6_OUT_LO			(0x0 << 1)
+#define RT5677_GPIO6_OUT_HI			(0x1 << 1)
+#define RT5677_GPIO6_P_MASK			(0x1 << 0)
+#define RT5677_GPIO6_P_SFT			0
+#define RT5677_GPIO6_P_NOR			(0x0 << 0)
+#define RT5677_GPIO6_P_INV			(0x1 << 0)
+
 /* Virtual DSP Mixer Control (0xf7 0xf8 0xf9) */
 #define RT5677_DSP_IB_01_H			(0x1 << 15)
 #define RT5677_DSP_IB_01_H_SFT			15
@@ -1393,6 +1501,11 @@
 #define RT5677_DSP_IB_9_L			(0x1 << 1)
 #define RT5677_DSP_IB_9_L_SFT			1
 
+/* General Control2 (0xfc)*/
+#define RT5677_GPIO5_FUNC_MASK			(0x1 << 9)
+#define RT5677_GPIO5_FUNC_GPIO			(0x0 << 9)
+#define RT5677_GPIO5_FUNC_DMIC			(0x1 << 9)
+
 /* System Clock Source */
 enum {
 	RT5677_SCLK_S_MCLK,
@@ -1418,6 +1531,16 @@
 	RT5677_AIFS,
 };
 
+enum {
+	RT5677_GPIO1,
+	RT5677_GPIO2,
+	RT5677_GPIO3,
+	RT5677_GPIO4,
+	RT5677_GPIO5,
+	RT5677_GPIO6,
+	RT5677_GPIO_NUM,
+};
+
 struct rt5677_priv {
 	struct snd_soc_codec *codec;
 	struct rt5677_platform_data pdata;
@@ -1431,6 +1554,10 @@
 	int pll_src;
 	int pll_in;
 	int pll_out;
+	int pow_ldo2; /* POW_LDO2 pin */
+#ifdef CONFIG_GPIOLIB
+	struct gpio_chip gpio_chip;
+#endif
 };
 
 #endif /* __RT5677_H__ */
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index e997d27..6bb77d7 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -626,6 +626,9 @@
 		} else {
 			dev_err(codec->dev,
 				"PLL not supported in slave mode\n");
+			dev_err(codec->dev, "%d ratio is not supported. "
+				"SYS_MCLK needs to be 256, 384 or 512 * fs\n",
+				sgtl5000->sysclk / sys_fs);
 			return -EINVAL;
 		}
 	}
@@ -1073,26 +1076,6 @@
 	}
 }
 
-#ifdef CONFIG_SUSPEND
-static int sgtl5000_suspend(struct snd_soc_codec *codec)
-{
-	sgtl5000_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-	return 0;
-}
-
-static int sgtl5000_resume(struct snd_soc_codec *codec)
-{
-	/* Bring the codec back up to standby to enable regulators */
-	sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-	return 0;
-}
-#else
-#define sgtl5000_suspend NULL
-#define sgtl5000_resume  NULL
-#endif	/* CONFIG_SUSPEND */
-
 /*
  * sgtl5000 has 3 internal power supplies:
  * 1. VAG, normally set to vdda/2
@@ -1352,11 +1335,6 @@
 	 */
 	snd_soc_write(codec, SGTL5000_DAP_CTRL, 0);
 
-	/* leading to standby state */
-	ret = sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-	if (ret)
-		goto err;
-
 	return 0;
 
 err:
@@ -1373,8 +1351,6 @@
 {
 	struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
 
-	sgtl5000_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
 	regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
 						sgtl5000->supplies);
 	regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
@@ -1387,9 +1363,8 @@
 static struct snd_soc_codec_driver sgtl5000_driver = {
 	.probe = sgtl5000_probe,
 	.remove = sgtl5000_remove,
-	.suspend = sgtl5000_suspend,
-	.resume = sgtl5000_resume,
 	.set_bias_level = sgtl5000_set_bias_level,
+	.suspend_bias_off = true,
 	.controls = sgtl5000_snd_controls,
 	.num_controls = ARRAY_SIZE(sgtl5000_snd_controls),
 	.dapm_widgets = sgtl5000_dapm_widgets,
@@ -1442,6 +1417,7 @@
 {
 	struct sgtl5000_priv *sgtl5000;
 	int ret, reg, rev;
+	unsigned int mclk;
 
 	sgtl5000 = devm_kzalloc(&client->dev, sizeof(struct sgtl5000_priv),
 								GFP_KERNEL);
@@ -1465,6 +1441,14 @@
 		return ret;
 	}
 
+	/* SGTL5000 SYS_MCLK should be between 8 and 27 MHz */
+	mclk = clk_get_rate(sgtl5000->mclk);
+	if (mclk < 8000000 || mclk > 27000000) {
+		dev_err(&client->dev, "Invalid SYS_CLK frequency: %u.%03uMHz\n",
+			mclk / 1000000, mclk / 1000 % 1000);
+		return -EINVAL;
+	}
+
 	ret = clk_prepare_enable(sgtl5000->mclk);
 	if (ret)
 		return ret;
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c
index e8680be..67ea55a 100644
--- a/sound/soc/codecs/ssm2518.c
+++ b/sound/soc/codecs/ssm2518.c
@@ -646,17 +646,6 @@
 	.ops = &ssm2518_dai_ops,
 };
 
-static int ssm2518_probe(struct snd_soc_codec *codec)
-{
-	return ssm2518_set_bias_level(codec, SND_SOC_BIAS_OFF);
-}
-
-static int ssm2518_remove(struct snd_soc_codec *codec)
-{
-	ssm2518_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	return 0;
-}
-
 static int ssm2518_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 	int source, unsigned int freq, int dir)
 {
@@ -727,8 +716,6 @@
 }
 
 static struct snd_soc_codec_driver ssm2518_codec_driver = {
-	.probe = ssm2518_probe,
-	.remove = ssm2518_remove,
 	.set_bias_level = ssm2518_set_bias_level,
 	.set_sysclk = ssm2518_set_sysclk,
 	.idle_bias_off = true,
diff --git a/sound/soc/codecs/ssm2602-i2c.c b/sound/soc/codecs/ssm2602-i2c.c
index abd63d5..0d9779d 100644
--- a/sound/soc/codecs/ssm2602-i2c.c
+++ b/sound/soc/codecs/ssm2602-i2c.c
@@ -41,10 +41,19 @@
 };
 MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
 
+static const struct of_device_id ssm2602_of_match[] = {
+	{ .compatible = "adi,ssm2602", },
+	{ .compatible = "adi,ssm2603", },
+	{ .compatible = "adi,ssm2604", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ssm2602_of_match);
+
 static struct i2c_driver ssm2602_i2c_driver = {
 	.driver = {
 		.name = "ssm2602",
 		.owner = THIS_MODULE,
+		.of_match_table = ssm2602_of_match,
 	},
 	.probe = ssm2602_i2c_probe,
 	.remove = ssm2602_i2c_remove,
diff --git a/sound/soc/codecs/ssm2602-spi.c b/sound/soc/codecs/ssm2602-spi.c
index 2bf55e2..b5df14f 100644
--- a/sound/soc/codecs/ssm2602-spi.c
+++ b/sound/soc/codecs/ssm2602-spi.c
@@ -26,10 +26,17 @@
 	return 0;
 }
 
+static const struct of_device_id ssm2602_of_match[] = {
+	{ .compatible = "adi,ssm2602", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ssm2602_of_match);
+
 static struct spi_driver ssm2602_spi_driver = {
 	.driver = {
 		.name	= "ssm2602",
 		.owner	= THIS_MODULE,
+		.of_match_table = ssm2602_of_match,
 	},
 	.probe		= ssm2602_spi_probe,
 	.remove		= ssm2602_spi_remove,
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 4021cd4..314eaec 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -192,7 +192,7 @@
 };
 
 static const unsigned int ssm2602_rates_11289600[] = {
-	8000, 44100, 88200,
+	8000, 11025, 22050, 44100, 88200,
 };
 
 static const struct snd_pcm_hw_constraint_list ssm2602_constraints_11289600 = {
@@ -237,6 +237,16 @@
 	{18432000, 96000, SSM2602_COEFF_SRATE(0x7, 0x1, 0x0)},
 	{12000000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x1)},
 
+	/* 11.025k */
+	{11289600, 11025, SSM2602_COEFF_SRATE(0xc, 0x0, 0x0)},
+	{16934400, 11025, SSM2602_COEFF_SRATE(0xc, 0x1, 0x0)},
+	{12000000, 11025, SSM2602_COEFF_SRATE(0xc, 0x1, 0x1)},
+
+	/* 22.05k */
+	{11289600, 22050, SSM2602_COEFF_SRATE(0xd, 0x0, 0x0)},
+	{16934400, 22050, SSM2602_COEFF_SRATE(0xd, 0x1, 0x0)},
+	{12000000, 22050, SSM2602_COEFF_SRATE(0xd, 0x1, 0x1)},
+
 	/* 44.1k */
 	{11289600, 44100, SSM2602_COEFF_SRATE(0x8, 0x0, 0x0)},
 	{16934400, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x0)},
@@ -467,7 +477,8 @@
 	return 0;
 }
 
-#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
 		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
 		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
 		SNDRV_PCM_RATE_96000)
@@ -502,18 +513,11 @@
 	.symmetric_samplebits = 1,
 };
 
-static int ssm2602_suspend(struct snd_soc_codec *codec)
-{
-	ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	return 0;
-}
-
 static int ssm2602_resume(struct snd_soc_codec *codec)
 {
 	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 
 	regcache_sync(ssm2602->regmap);
-	ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
 	return 0;
 }
@@ -586,27 +590,14 @@
 		break;
 	}
 
-	if (ret)
-		return ret;
-
-	ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-	return 0;
-}
-
-/* remove everything here */
-static int ssm2602_remove(struct snd_soc_codec *codec)
-{
-	ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	return 0;
+	return ret;
 }
 
 static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
 	.probe =	ssm260x_codec_probe,
-	.remove =	ssm2602_remove,
-	.suspend =	ssm2602_suspend,
 	.resume =	ssm2602_resume,
 	.set_bias_level = ssm2602_set_bias_level,
+	.suspend_bias_off = true,
 
 	.controls = ssm260x_snd_controls,
 	.num_controls = ARRAY_SIZE(ssm260x_snd_controls),
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c
new file mode 100644
index 0000000..4b5c17f
--- /dev/null
+++ b/sound/soc/codecs/ssm4567.c
@@ -0,0 +1,343 @@
+/*
+ * SSM4567 amplifier audio driver
+ *
+ * Copyright 2014 Google Chromium project.
+ *  Author: Anatol Pomozov <anatol@chromium.org>
+ *
+ * Based on code copyright/by:
+ *   Copyright 2013 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#define SSM4567_REG_POWER_CTRL		0x00
+#define SSM4567_REG_AMP_SNS_CTRL		0x01
+#define SSM4567_REG_DAC_CTRL		0x02
+#define SSM4567_REG_DAC_VOLUME		0x03
+#define SSM4567_REG_SAI_CTRL_1		0x04
+#define SSM4567_REG_SAI_CTRL_2		0x05
+#define SSM4567_REG_SAI_PLACEMENT_1		0x06
+#define SSM4567_REG_SAI_PLACEMENT_2		0x07
+#define SSM4567_REG_SAI_PLACEMENT_3		0x08
+#define SSM4567_REG_SAI_PLACEMENT_4		0x09
+#define SSM4567_REG_SAI_PLACEMENT_5		0x0a
+#define SSM4567_REG_SAI_PLACEMENT_6		0x0b
+#define SSM4567_REG_BATTERY_V_OUT		0x0c
+#define SSM4567_REG_LIMITER_CTRL_1		0x0d
+#define SSM4567_REG_LIMITER_CTRL_2		0x0e
+#define SSM4567_REG_LIMITER_CTRL_3		0x0f
+#define SSM4567_REG_STATUS_1		0x10
+#define SSM4567_REG_STATUS_2		0x11
+#define SSM4567_REG_FAULT_CTRL		0x12
+#define SSM4567_REG_PDM_CTRL		0x13
+#define SSM4567_REG_MCLK_RATIO		0x14
+#define SSM4567_REG_BOOST_CTRL_1		0x15
+#define SSM4567_REG_BOOST_CTRL_2		0x16
+#define SSM4567_REG_SOFT_RESET		0xff
+
+/* POWER_CTRL */
+#define SSM4567_POWER_APWDN_EN		BIT(7)
+#define SSM4567_POWER_BSNS_PWDN		BIT(6)
+#define SSM4567_POWER_VSNS_PWDN		BIT(5)
+#define SSM4567_POWER_ISNS_PWDN		BIT(4)
+#define SSM4567_POWER_BOOST_PWDN		BIT(3)
+#define SSM4567_POWER_AMP_PWDN		BIT(2)
+#define SSM4567_POWER_VBAT_ONLY		BIT(1)
+#define SSM4567_POWER_SPWDN			BIT(0)
+
+/* DAC_CTRL */
+#define SSM4567_DAC_HV			BIT(7)
+#define SSM4567_DAC_MUTE		BIT(6)
+#define SSM4567_DAC_HPF			BIT(5)
+#define SSM4567_DAC_LPM			BIT(4)
+#define SSM4567_DAC_FS_MASK	0x7
+#define SSM4567_DAC_FS_8000_12000	0x0
+#define SSM4567_DAC_FS_16000_24000	0x1
+#define SSM4567_DAC_FS_32000_48000	0x2
+#define SSM4567_DAC_FS_64000_96000	0x3
+#define SSM4567_DAC_FS_128000_192000	0x4
+
+struct ssm4567 {
+	struct regmap *regmap;
+};
+
+static const struct reg_default ssm4567_reg_defaults[] = {
+	{ SSM4567_REG_POWER_CTRL,	0x81 },
+	{ SSM4567_REG_AMP_SNS_CTRL, 0x09 },
+	{ SSM4567_REG_DAC_CTRL, 0x32 },
+	{ SSM4567_REG_DAC_VOLUME, 0x40 },
+	{ SSM4567_REG_SAI_CTRL_1, 0x00 },
+	{ SSM4567_REG_SAI_CTRL_2, 0x08 },
+	{ SSM4567_REG_SAI_PLACEMENT_1, 0x01 },
+	{ SSM4567_REG_SAI_PLACEMENT_2, 0x20 },
+	{ SSM4567_REG_SAI_PLACEMENT_3, 0x32 },
+	{ SSM4567_REG_SAI_PLACEMENT_4, 0x07 },
+	{ SSM4567_REG_SAI_PLACEMENT_5, 0x07 },
+	{ SSM4567_REG_SAI_PLACEMENT_6, 0x07 },
+	{ SSM4567_REG_BATTERY_V_OUT, 0x00 },
+	{ SSM4567_REG_LIMITER_CTRL_1, 0xa4 },
+	{ SSM4567_REG_LIMITER_CTRL_2, 0x73 },
+	{ SSM4567_REG_LIMITER_CTRL_3, 0x00 },
+	{ SSM4567_REG_STATUS_1, 0x00 },
+	{ SSM4567_REG_STATUS_2, 0x00 },
+	{ SSM4567_REG_FAULT_CTRL, 0x30 },
+	{ SSM4567_REG_PDM_CTRL, 0x40 },
+	{ SSM4567_REG_MCLK_RATIO, 0x11 },
+	{ SSM4567_REG_BOOST_CTRL_1, 0x03 },
+	{ SSM4567_REG_BOOST_CTRL_2, 0x00 },
+	{ SSM4567_REG_SOFT_RESET, 0x00 },
+};
+
+
+static bool ssm4567_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case SSM4567_REG_POWER_CTRL ... SSM4567_REG_BOOST_CTRL_2:
+		return true;
+	default:
+		return false;
+	}
+
+}
+
+static bool ssm4567_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case SSM4567_REG_POWER_CTRL ... SSM4567_REG_SAI_PLACEMENT_6:
+	case SSM4567_REG_LIMITER_CTRL_1 ... SSM4567_REG_LIMITER_CTRL_3:
+	case SSM4567_REG_FAULT_CTRL ... SSM4567_REG_BOOST_CTRL_2:
+	/* The datasheet states that soft reset register is read-only,
+	 * but logically it is write-only. */
+	case SSM4567_REG_SOFT_RESET:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool ssm4567_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case SSM4567_REG_BATTERY_V_OUT:
+	case SSM4567_REG_STATUS_1 ... SSM4567_REG_STATUS_2:
+	case SSM4567_REG_SOFT_RESET:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_MINMAX_MUTE(ssm4567_vol_tlv, -7125, 2400);
+
+static const struct snd_kcontrol_new ssm4567_snd_controls[] = {
+	SOC_SINGLE_TLV("Master Playback Volume", SSM4567_REG_DAC_VOLUME, 0,
+		0xff, 1, ssm4567_vol_tlv),
+	SOC_SINGLE("DAC Low Power Mode Switch", SSM4567_REG_DAC_CTRL, 4, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget ssm4567_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM4567_REG_POWER_CTRL, 2, 1),
+
+	SND_SOC_DAPM_OUTPUT("OUT"),
+};
+
+static const struct snd_soc_dapm_route ssm4567_routes[] = {
+	{ "OUT", NULL, "DAC" },
+};
+
+static int ssm4567_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 ssm4567 *ssm4567 = snd_soc_codec_get_drvdata(codec);
+	unsigned int rate = params_rate(params);
+	unsigned int dacfs;
+
+	if (rate >= 8000 && rate <= 12000)
+		dacfs = SSM4567_DAC_FS_8000_12000;
+	else if (rate >= 16000 && rate <= 24000)
+		dacfs = SSM4567_DAC_FS_16000_24000;
+	else if (rate >= 32000 && rate <= 48000)
+		dacfs = SSM4567_DAC_FS_32000_48000;
+	else if (rate >= 64000 && rate <= 96000)
+		dacfs = SSM4567_DAC_FS_64000_96000;
+	else if (rate >= 128000 && rate <= 192000)
+		dacfs = SSM4567_DAC_FS_128000_192000;
+	else
+		return -EINVAL;
+
+	return regmap_update_bits(ssm4567->regmap, SSM4567_REG_DAC_CTRL,
+				SSM4567_DAC_FS_MASK, dacfs);
+}
+
+static int ssm4567_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct ssm4567 *ssm4567 = snd_soc_codec_get_drvdata(dai->codec);
+	unsigned int val;
+
+	val = mute ? SSM4567_DAC_MUTE : 0;
+	return regmap_update_bits(ssm4567->regmap, SSM4567_REG_DAC_CTRL,
+			SSM4567_DAC_MUTE, val);
+}
+
+static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable)
+{
+	int ret = 0;
+
+	if (!enable) {
+		ret = regmap_update_bits(ssm4567->regmap,
+			SSM4567_REG_POWER_CTRL,
+			SSM4567_POWER_SPWDN, SSM4567_POWER_SPWDN);
+		regcache_mark_dirty(ssm4567->regmap);
+	}
+
+	regcache_cache_only(ssm4567->regmap, !enable);
+
+	if (enable) {
+		ret = regmap_update_bits(ssm4567->regmap,
+			SSM4567_REG_POWER_CTRL,
+			SSM4567_POWER_SPWDN, 0x00);
+		regcache_sync(ssm4567->regmap);
+	}
+
+	return ret;
+}
+
+static int ssm4567_set_bias_level(struct snd_soc_codec *codec,
+	enum snd_soc_bias_level level)
+{
+	struct ssm4567 *ssm4567 = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+			ret = ssm4567_set_power(ssm4567, true);
+		break;
+	case SND_SOC_BIAS_OFF:
+		ret = ssm4567_set_power(ssm4567, false);
+		break;
+	}
+
+	if (ret)
+		return ret;
+
+	codec->dapm.bias_level = level;
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops ssm4567_dai_ops = {
+	.hw_params	= ssm4567_hw_params,
+	.digital_mute	= ssm4567_mute,
+};
+
+static struct snd_soc_dai_driver ssm4567_dai = {
+	.name = "ssm4567-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000_192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+			SNDRV_PCM_FMTBIT_S32,
+	},
+	.ops = &ssm4567_dai_ops,
+};
+
+static struct snd_soc_codec_driver ssm4567_codec_driver = {
+	.set_bias_level = ssm4567_set_bias_level,
+	.idle_bias_off = true,
+
+	.controls = ssm4567_snd_controls,
+	.num_controls = ARRAY_SIZE(ssm4567_snd_controls),
+	.dapm_widgets = ssm4567_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(ssm4567_dapm_widgets),
+	.dapm_routes = ssm4567_routes,
+	.num_dapm_routes = ARRAY_SIZE(ssm4567_routes),
+};
+
+static const struct regmap_config ssm4567_regmap_config = {
+	.val_bits = 8,
+	.reg_bits = 8,
+
+	.max_register = SSM4567_REG_SOFT_RESET,
+	.readable_reg = ssm4567_readable_reg,
+	.writeable_reg = ssm4567_writeable_reg,
+	.volatile_reg = ssm4567_volatile_reg,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = ssm4567_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(ssm4567_reg_defaults),
+};
+
+static int ssm4567_i2c_probe(struct i2c_client *i2c,
+	const struct i2c_device_id *id)
+{
+	struct ssm4567 *ssm4567;
+	int ret;
+
+	ssm4567 = devm_kzalloc(&i2c->dev, sizeof(*ssm4567), GFP_KERNEL);
+	if (ssm4567 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, ssm4567);
+
+	ssm4567->regmap = devm_regmap_init_i2c(i2c, &ssm4567_regmap_config);
+	if (IS_ERR(ssm4567->regmap))
+		return PTR_ERR(ssm4567->regmap);
+
+	ret = regmap_write(ssm4567->regmap, SSM4567_REG_SOFT_RESET, 0x00);
+	if (ret)
+		return ret;
+
+	ret = ssm4567_set_power(ssm4567, false);
+	if (ret)
+		return ret;
+
+	return snd_soc_register_codec(&i2c->dev, &ssm4567_codec_driver,
+			&ssm4567_dai, 1);
+}
+
+static int ssm4567_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	return 0;
+}
+
+static const struct i2c_device_id ssm4567_i2c_ids[] = {
+	{ "ssm4567", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ssm4567_i2c_ids);
+
+static struct i2c_driver ssm4567_driver = {
+	.driver = {
+		.name = "ssm4567",
+		.owner = THIS_MODULE,
+	},
+	.probe = ssm4567_i2c_probe,
+	.remove = ssm4567_i2c_remove,
+	.id_table = ssm4567_i2c_ids,
+};
+module_i2c_driver(ssm4567_driver);
+
+MODULE_DESCRIPTION("ASoC SSM4567 driver");
+MODULE_AUTHOR("Anatol Pomozov <anatol@chromium.org>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index 23b3296..f039dc8 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -78,6 +78,44 @@
 	unsigned int mclk;
 };
 
+/* Input mux controls */
+static const char *tas2552_input_texts[] = {
+	"Digital", "Analog"
+};
+
+static SOC_ENUM_SINGLE_DECL(tas2552_input_mux_enum, TAS2552_CFG_3, 7,
+			    tas2552_input_texts);
+
+static const struct snd_kcontrol_new tas2552_input_mux_control[] = {
+	SOC_DAPM_ENUM("Input selection", tas2552_input_mux_enum)
+};
+
+static const struct snd_soc_dapm_widget tas2552_dapm_widgets[] =
+{
+	SND_SOC_DAPM_INPUT("IN"),
+
+	/* MUX Controls */
+	SND_SOC_DAPM_MUX("Input selection", SND_SOC_NOPM, 0, 0,
+				tas2552_input_mux_control),
+
+	SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_OUT_DRV("ClassD", TAS2552_CFG_2, 7, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL", TAS2552_CFG_2, 3, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("OUT")
+};
+
+static const struct snd_soc_dapm_route tas2552_audio_map[] = {
+	{"DAC", NULL, "DAC IN"},
+	{"Input selection", "Digital", "DAC"},
+	{"Input selection", "Analog", "IN"},
+	{"ClassD", NULL, "Input selection"},
+	{"OUT", NULL, "ClassD"},
+	{"ClassD", NULL, "PLL"},
+};
+
+#ifdef CONFIG_PM_RUNTIME
 static void tas2552_sw_shutdown(struct tas2552_data *tas_data, int sw_shutdown)
 {
 	u8 cfg1_reg;
@@ -90,6 +128,7 @@
 	snd_soc_update_bits(tas_data->codec, TAS2552_CFG_1,
 						 TAS2552_SWS_MASK, cfg1_reg);
 }
+#endif
 
 static int tas2552_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
@@ -101,10 +140,6 @@
 	int d;
 	u8 p, j;
 
-	/* Turn on Class D amplifier */
-	snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_CLASSD_EN_MASK,
-						TAS2552_CLASSD_EN);
-
 	if (!tas2552->mclk)
 		return -EINVAL;
 
@@ -147,9 +182,6 @@
 
 	}
 
-	snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE,
-						TAS2552_PLL_ENABLE);
-
 	return 0;
 }
 
@@ -269,19 +301,10 @@
 			   NULL)
 };
 
-static void tas2552_shutdown(struct snd_pcm_substream *substream,
-			   struct snd_soc_dai *dai)
-{
-	struct snd_soc_codec *codec = dai->codec;
-
-	snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0);
-}
-
 static struct snd_soc_dai_ops tas2552_speaker_dai_ops = {
 	.hw_params	= tas2552_hw_params,
 	.set_sysclk	= tas2552_set_dai_sysclk,
 	.set_fmt	= tas2552_set_dai_fmt,
-	.shutdown	= tas2552_shutdown,
 	.digital_mute = tas2552_mute,
 };
 
@@ -294,7 +317,7 @@
 	{
 		.name = "tas2552-amplifier",
 		.playback = {
-			.stream_name = "Speaker",
+			.stream_name = "Playback",
 			.channels_min = 2,
 			.channels_max = 2,
 			.rates = SNDRV_PCM_RATE_8000_192000,
@@ -312,6 +335,7 @@
 static const struct snd_kcontrol_new tas2552_snd_controls[] = {
 	SOC_SINGLE_TLV("Speaker Driver Playback Volume",
 			 TAS2552_PGA_GAIN, 0, 0x1f, 1, dac_tlv),
+	SOC_DAPM_SINGLE("Playback AMP", SND_SOC_NOPM, 0, 1, 0),
 };
 
 static const struct reg_default tas2552_init_regs[] = {
@@ -321,6 +345,7 @@
 static int tas2552_codec_probe(struct snd_soc_codec *codec)
 {
 	struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	int ret;
 
 	tas2552->codec = codec;
@@ -362,9 +387,14 @@
 		goto patch_fail;
 	}
 
-	snd_soc_write(codec, TAS2552_CFG_2, TAS2552_CLASSD_EN |
-				  TAS2552_BOOST_EN | TAS2552_APT_EN |
-				  TAS2552_LIM_EN);
+	snd_soc_write(codec, TAS2552_CFG_2, TAS2552_BOOST_EN |
+				  TAS2552_APT_EN | TAS2552_LIM_EN);
+
+	snd_soc_dapm_new_controls(dapm, tas2552_dapm_widgets,
+				ARRAY_SIZE(tas2552_dapm_widgets));
+	snd_soc_dapm_add_routes(dapm, tas2552_audio_map,
+				ARRAY_SIZE(tas2552_audio_map));
+
 	return 0;
 
 patch_fail:
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index aea9e1f..145fe5b 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -167,13 +167,13 @@
 	struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES];
 	struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES];
 	unsigned int sysclk;
+	u8 p_div;
 	int rate_div_line;
 };
 
 struct aic31xx_rate_divs {
-	u32 mclk;
+	u32 mclk_p;
 	u32 rate;
-	u8 p_val;
 	u8 pll_j;
 	u16 pll_d;
 	u16 dosr;
@@ -186,62 +186,51 @@
 
 /* ADC dividers can be disabled by cofiguring them to 0 */
 static const struct aic31xx_rate_divs aic31xx_divs[] = {
-	/* mclk      rate  pll: p  j	 d     dosr ndac mdac  aors nadc madc */
+	/* mclk/p    rate  pll: j     d        dosr ndac mdac  aors nadc madc */
 	/* 8k rate */
-	{12000000,   8000,	1, 8, 1920,	128,  48,  2,	128,  48,  2},
-	{12000000,   8000,	1, 8, 1920,	128,  32,  3,	128,  32,  3},
-	{24000000,   8000,	2, 8, 1920,	128,  48,  2,	128,  48,  2},
-	{25000000,   8000,	2, 7, 8643,	128,  48,  2,	128,  48,  2},
+	{12000000,   8000,	8, 1920,	128,  48,  2,	128,  48,  2},
+	{12000000,   8000,	8, 1920,	128,  32,  3,	128,  32,  3},
+	{12500000,   8000,	7, 8643,	128,  48,  2,	128,  48,  2},
 	/* 11.025k rate */
-	{12000000,  11025,	1, 7, 5264,	128,  32,  2,	128,  32,  2},
-	{12000000,  11025,	1, 8, 4672,	128,  24,  3,	128,  24,  3},
-	{24000000,  11025,	2, 7, 5264,	128,  32,  2,	128,  32,  2},
-	{25000000,  11025,	2, 7, 2253,	128,  32,  2,	128,  32,  2},
+	{12000000,  11025,	7, 5264,	128,  32,  2,	128,  32,  2},
+	{12000000,  11025,	8, 4672,	128,  24,  3,	128,  24,  3},
+	{12500000,  11025,	7, 2253,	128,  32,  2,	128,  32,  2},
 	/* 16k rate */
-	{12000000,  16000,	1, 8, 1920,	128,  24,  2,	128,  24,  2},
-	{12000000,  16000,	1, 8, 1920,	128,  16,  3,	128,  16,  3},
-	{24000000,  16000,	2, 8, 1920,	128,  24,  2,	128,  24,  2},
-	{25000000,  16000,	2, 7, 8643,	128,  24,  2,	128,  24,  2},
+	{12000000,  16000,	8, 1920,	128,  24,  2,	128,  24,  2},
+	{12000000,  16000,	8, 1920,	128,  16,  3,	128,  16,  3},
+	{12500000,  16000,	7, 8643,	128,  24,  2,	128,  24,  2},
 	/* 22.05k rate */
-	{12000000,  22050,	1, 7, 5264,	128,  16,  2,	128,  16,  2},
-	{12000000,  22050,	1, 8, 4672,	128,  12,  3,	128,  12,  3},
-	{24000000,  22050,	2, 7, 5264,	128,  16,  2,	128,  16,  2},
-	{25000000,  22050,	2, 7, 2253,	128,  16,  2,	128,  16,  2},
+	{12000000,  22050,	7, 5264,	128,  16,  2,	128,  16,  2},
+	{12000000,  22050,	8, 4672,	128,  12,  3,	128,  12,  3},
+	{12500000,  22050,	7, 2253,	128,  16,  2,	128,  16,  2},
 	/* 32k rate */
-	{12000000,  32000,	1, 8, 1920,	128,  12,  2,	128,  12,  2},
-	{12000000,  32000,	1, 8, 1920,	128,   8,  3,	128,   8,  3},
-	{24000000,  32000,	2, 8, 1920,	128,  12,  2,	128,  12,  2},
-	{25000000,  32000,	2, 7, 8643,	128,  12,  2,	128,  12,  2},
+	{12000000,  32000,	8, 1920,	128,  12,  2,	128,  12,  2},
+	{12000000,  32000,	8, 1920,	128,   8,  3,	128,   8,  3},
+	{12500000,  32000,	7, 8643,	128,  12,  2,	128,  12,  2},
 	/* 44.1k rate */
-	{12000000,  44100,	1, 7, 5264,	128,   8,  2,	128,   8,  2},
-	{12000000,  44100,	1, 8, 4672,	128,   6,  3,	128,   6,  3},
-	{24000000,  44100,	2, 7, 5264,	128,   8,  2,	128,   8,  2},
-	{25000000,  44100,	2, 7, 2253,	128,   8,  2,	128,   8,  2},
+	{12000000,  44100,	7, 5264,	128,   8,  2,	128,   8,  2},
+	{12000000,  44100,	8, 4672,	128,   6,  3,	128,   6,  3},
+	{12500000,  44100,	7, 2253,	128,   8,  2,	128,   8,  2},
 	/* 48k rate */
-	{12000000,  48000,	1, 8, 1920,	128,   8,  2,	128,   8,  2},
-	{12000000,  48000,	1, 7, 6800,	 96,   5,  4,	 96,   5,  4},
-	{24000000,  48000,	2, 8, 1920,	128,   8,  2,	128,   8,  2},
-	{25000000,  48000,	2, 7, 8643,	128,   8,  2,	128,   8,  2},
+	{12000000,  48000,	8, 1920,	128,   8,  2,	128,   8,  2},
+	{12000000,  48000,	7, 6800,	 96,   5,  4,	 96,   5,  4},
+	{12500000,  48000,	7, 8643,	128,   8,  2,	128,   8,  2},
 	/* 88.2k rate */
-	{12000000,  88200,	1, 7, 5264,	 64,   8,  2,	 64,   8,  2},
-	{12000000,  88200,	1, 8, 4672,	 64,   6,  3,	 64,   6,  3},
-	{24000000,  88200,	2, 7, 5264,	 64,   8,  2,	 64,   8,  2},
-	{25000000,  88200,	2, 7, 2253,	 64,   8,  2,	 64,   8,  2},
+	{12000000,  88200,	7, 5264,	 64,   8,  2,	 64,   8,  2},
+	{12000000,  88200,	8, 4672,	 64,   6,  3,	 64,   6,  3},
+	{12500000,  88200,	7, 2253,	 64,   8,  2,	 64,   8,  2},
 	/* 96k rate */
-	{12000000,  96000,	1, 8, 1920,	 64,   8,  2,	 64,   8,  2},
-	{12000000,  96000,	1, 7, 6800,	 48,   5,  4,	 48,   5,  4},
-	{24000000,  96000,	2, 8, 1920,	 64,   8,  2,	 64,   8,  2},
-	{25000000,  96000,	2, 7, 8643,	 64,   8,  2,	 64,   8,  2},
+	{12000000,  96000,	8, 1920,	 64,   8,  2,	 64,   8,  2},
+	{12000000,  96000,	7, 6800,	 48,   5,  4,	 48,   5,  4},
+	{12500000,  96000,	7, 8643,	 64,   8,  2,	 64,   8,  2},
 	/* 176.4k rate */
-	{12000000, 176400,	1, 7, 5264,	 32,   8,  2,	 32,   8,  2},
-	{12000000, 176400,	1, 8, 4672,	 32,   6,  3,	 32,   6,  3},
-	{24000000, 176400,	2, 7, 5264,	 32,   8,  2,	 32,   8,  2},
-	{25000000, 176400,	2, 7, 2253,	 32,   8,  2,	 32,   8,  2},
+	{12000000, 176400,	7, 5264,	 32,   8,  2,	 32,   8,  2},
+	{12000000, 176400,	8, 4672,	 32,   6,  3,	 32,   6,  3},
+	{12500000, 176400,	7, 2253,	 32,   8,  2,	 32,   8,  2},
 	/* 192k rate */
-	{12000000, 192000,	1, 8, 1920,	 32,   8,  2,	 32,   8,  2},
-	{12000000, 192000,	1, 7, 6800,	 24,   5,  4,	 24,   5,  4},
-	{24000000, 192000,	2, 8, 1920,	 32,   8,  2,	 32,   8,  2},
-	{25000000, 192000,	2, 7, 8643,	 32,   8,  2,	 32,   8,  2},
+	{12000000, 192000,	8, 1920,	 32,   8,  2,	 32,   8,  2},
+	{12000000, 192000,	7, 6800,	 24,   5,  4,	 24,   5,  4},
+	{12500000, 192000,	7, 8643,	 32,   8,  2,	 32,   8,  2},
 };
 
 static const char * const ldac_in_text[] = {
@@ -692,6 +681,7 @@
 {
 	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
 	int bclk_score = snd_soc_params_to_frame_size(params);
+	int mclk_p = aic31xx->sysclk / aic31xx->p_div;
 	int bclk_n = 0;
 	int match = -1;
 	int i;
@@ -704,7 +694,7 @@
 
 	for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++) {
 		if (aic31xx_divs[i].rate == params_rate(params) &&
-		    aic31xx_divs[i].mclk == aic31xx->sysclk) {
+		    aic31xx_divs[i].mclk_p == mclk_p) {
 			int s =	(aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) %
 				snd_soc_params_to_frame_size(params);
 			int bn = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) /
@@ -738,7 +728,7 @@
 
 	/* PLL configuration */
 	snd_soc_update_bits(codec, AIC31XX_PLLPR, AIC31XX_PLL_MASK,
-			    (aic31xx_divs[i].p_val << 4) | 0x01);
+			    (aic31xx->p_div << 4) | 0x01);
 	snd_soc_write(codec, AIC31XX_PLLJ, aic31xx_divs[i].pll_j);
 
 	snd_soc_write(codec, AIC31XX_PLLDMSB,
@@ -772,7 +762,7 @@
 	dev_dbg(codec->dev,
 		"pll %d.%04d/%d dosr %d n %d m %d aosr %d n %d m %d bclk_n %d\n",
 		aic31xx_divs[i].pll_j, aic31xx_divs[i].pll_d,
-		aic31xx_divs[i].p_val, aic31xx_divs[i].dosr,
+		aic31xx->p_div, aic31xx_divs[i].dosr,
 		aic31xx_divs[i].ndac, aic31xx_divs[i].mdac,
 		aic31xx_divs[i].aosr, aic31xx_divs[i].nadc,
 		aic31xx_divs[i].madc, bclk_n);
@@ -840,7 +830,7 @@
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
 	u8 iface_reg1 = 0;
-	u8 iface_reg3 = 0;
+	u8 iface_reg2 = 0;
 	u8 dsp_a_val = 0;
 
 	dev_dbg(codec->dev, "## %s: fmt = 0x%x\n", __func__, fmt);
@@ -865,7 +855,7 @@
 		/* NOTE: BCLKINV bit value 1 equas NB and 0 equals IB */
 		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 		case SND_SOC_DAIFMT_NB_NF:
-			iface_reg3 |= AIC31XX_BCLKINV_MASK;
+			iface_reg2 |= AIC31XX_BCLKINV_MASK;
 			break;
 		case SND_SOC_DAIFMT_IB_NF:
 			break;
@@ -897,7 +887,7 @@
 			    dsp_a_val);
 	snd_soc_update_bits(codec, AIC31XX_IFACE2,
 			    AIC31XX_BCLKINV_MASK,
-			    iface_reg3);
+			    iface_reg2);
 
 	return 0;
 }
@@ -912,7 +902,16 @@
 	dev_dbg(codec->dev, "## %s: clk_id = %d, freq = %d, dir = %d\n",
 		__func__, clk_id, freq, dir);
 
-	for (i = 0; aic31xx_divs[i].mclk != freq; i++) {
+	for (i = 1; freq/i > 20000000 && i < 8; i++)
+		;
+	if (freq/i > 20000000) {
+		dev_err(aic31xx->dev, "%s: Too high mclk frequency %u\n",
+			__func__, freq);
+			return -EINVAL;
+	}
+	aic31xx->p_div = i;
+
+	for (i = 0; aic31xx_divs[i].mclk_p != freq/aic31xx->p_div; i++) {
 		if (i == ARRAY_SIZE(aic31xx_divs)) {
 			dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n",
 				__func__, freq);
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h
index 52ed57c..fe16c34 100644
--- a/sound/soc/codecs/tlv320aic31xx.h
+++ b/sound/soc/codecs/tlv320aic31xx.h
@@ -18,7 +18,8 @@
 #define AIC31XX_RATES	SNDRV_PCM_RATE_8000_192000
 
 #define AIC31XX_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
-			 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+			 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE \
+			 | SNDRV_PCM_FMTBIT_S32_LE)
 
 
 #define AIC31XX_STEREO_CLASS_D_BIT	0x1
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 64f179e..f7c2a57 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -1121,6 +1121,7 @@
 static int aic3x_set_power(struct snd_soc_codec *codec, int power)
 {
 	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+	unsigned int pll_c, pll_d;
 	int ret;
 
 	if (power) {
@@ -1138,6 +1139,18 @@
 		/* Sync reg_cache with the hardware */
 		regcache_cache_only(aic3x->regmap, false);
 		regcache_sync(aic3x->regmap);
+
+		/* Rewrite paired PLL D registers in case cached sync skipped
+		 * writing one of them and thus caused other one also not
+		 * being written
+		 */
+		pll_c = snd_soc_read(codec, AIC3X_PLL_PROGC_REG);
+		pll_d = snd_soc_read(codec, AIC3X_PLL_PROGD_REG);
+		if (pll_c == aic3x_reg[AIC3X_PLL_PROGC_REG].def ||
+			pll_d == aic3x_reg[AIC3X_PLL_PROGD_REG].def) {
+			snd_soc_write(codec, AIC3X_PLL_PROGC_REG, pll_c);
+			snd_soc_write(codec, AIC3X_PLL_PROGD_REG, pll_d);
+		}
 	} else {
 		/*
 		 * Do soft reset to this codec instance in order to clear
@@ -1222,20 +1235,6 @@
 	.symmetric_rates = 1,
 };
 
-static int aic3x_suspend(struct snd_soc_codec *codec)
-{
-	aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-	return 0;
-}
-
-static int aic3x_resume(struct snd_soc_codec *codec)
-{
-	aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-	return 0;
-}
-
 static void aic3x_mono_init(struct snd_soc_codec *codec)
 {
 	/* DAC to Mono Line Out default volume and route to Output mixer */
@@ -1429,8 +1428,6 @@
 	.idle_bias_off = true,
 	.probe = aic3x_probe,
 	.remove = aic3x_remove,
-	.suspend = aic3x_suspend,
-	.resume = aic3x_resume,
 	.controls = aic3x_snd_controls,
 	.num_controls = ARRAY_SIZE(aic3x_snd_controls),
 	.dapm_widgets = aic3x_dapm_widgets,
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index 7bb0d36..a01ad62 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -2319,11 +2319,8 @@
 static void wm5100_free_gpio(struct i2c_client *i2c)
 {
 	struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c);
-	int ret;
 
-	ret = gpiochip_remove(&wm5100->gpio_chip);
-	if (ret != 0)
-		dev_err(&i2c->dev, "Failed to remove GPIOs: %d\n", ret);
+	gpiochip_remove(&wm5100->gpio_chip);
 }
 #else
 static void wm5100_init_gpio(struct i2c_client *i2c)
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index 3dfdcc4..628ec77 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -212,7 +212,7 @@
 {
 	struct snd_soc_dapm_context *dapm =
 	    container_of(work, struct snd_soc_dapm_context, delayed_work.work);
-	struct snd_soc_codec *codec = dapm->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
 	struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
 	struct wm8350_output *out1 = &wm8350_data->out1,
 	    *out2 = &wm8350_data->out2;
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index a237f16..31bb480 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.c
@@ -413,7 +413,6 @@
 	return 0;
 }
 #else
-#define wm8741_suspend NULL
 #define wm8741_resume NULL
 #endif
 
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index e54e097..21ca3a9 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -1433,7 +1433,7 @@
 	struct snd_soc_dapm_context *dapm =
 		container_of(work, struct snd_soc_dapm_context,
 			     delayed_work.work);
-	struct snd_soc_codec *codec = dapm->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
 	wm8753_set_bias_level(codec, dapm->bias_level);
 }
 
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index 0ea01df..3addc5f 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -518,23 +518,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8804_suspend(struct snd_soc_codec *codec)
-{
-	wm8804_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	return 0;
-}
-
-static int wm8804_resume(struct snd_soc_codec *codec)
-{
-	wm8804_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-	return 0;
-}
-#else
-#define wm8804_suspend NULL
-#define wm8804_resume NULL
-#endif
-
 static int wm8804_remove(struct snd_soc_codec *codec)
 {
 	struct wm8804_priv *wm8804;
@@ -671,8 +654,6 @@
 static struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
 	.probe = wm8804_probe,
 	.remove = wm8804_remove,
-	.suspend = wm8804_suspend,
-	.resume = wm8804_resume,
 	.set_bias_level = wm8804_set_bias_level,
 	.idle_bias_off = true,
 
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index aa09848..c038b3e 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -1877,11 +1877,7 @@
 
 static void wm8903_free_gpio(struct wm8903_priv *wm8903)
 {
-	int ret;
-
-	ret = gpiochip_remove(&wm8903->gpio_chip);
-	if (ret != 0)
-		dev_err(wm8903->dev, "Failed to remove GPIOs: %d\n", ret);
+	gpiochip_remove(&wm8903->gpio_chip);
 }
 #else
 static void wm8903_init_gpio(struct wm8903_priv *wm8903)
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 1098ae3..9077411e 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -3398,11 +3398,8 @@
 static void wm8962_free_gpio(struct snd_soc_codec *codec)
 {
 	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
-	int ret;
 
-	ret = gpiochip_remove(&wm8962->gpio_chip);
-	if (ret != 0)
-		dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
+	gpiochip_remove(&wm8962->gpio_chip);
 }
 #else
 static void wm8962_init_gpio(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index 0499cd4..39ddb9b 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -615,7 +615,7 @@
 	struct snd_soc_dapm_context *dapm =
 		container_of(work, struct snd_soc_dapm_context,
 			     delayed_work.work);
-	struct snd_soc_codec *codec = dapm->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
 	wm8971_set_bias_level(codec, codec->dapm.bias_level);
 }
 
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 6cc0566..1fcb9f3 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -4082,17 +4082,23 @@
 
 	switch (control->type) {
 	case WM8994:
-		if (wm8994->micdet_irq) {
+		if (wm8994->micdet_irq)
 			ret = request_threaded_irq(wm8994->micdet_irq, NULL,
 						   wm8994_mic_irq,
 						   IRQF_TRIGGER_RISING,
 						   "Mic1 detect",
 						   wm8994);
-			if (ret != 0)
-				dev_warn(codec->dev,
-					 "Failed to request Mic1 detect IRQ: %d\n",
-					 ret);
-		}
+		 else
+			ret = wm8994_request_irq(wm8994->wm8994,
+					WM8994_IRQ_MIC1_DET,
+					wm8994_mic_irq, "Mic 1 detect",
+					wm8994);
+
+		if (ret != 0)
+			dev_warn(codec->dev,
+				 "Failed to request Mic1 detect IRQ: %d\n",
+				 ret);
+
 
 		ret = wm8994_request_irq(wm8994->wm8994,
 					 WM8994_IRQ_MIC1_SHRT,
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
index cae4ac5..1288ede 100644
--- a/sound/soc/codecs/wm8995.c
+++ b/sound/soc/codecs/wm8995.c
@@ -1998,23 +1998,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8995_suspend(struct snd_soc_codec *codec)
-{
-	wm8995_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	return 0;
-}
-
-static int wm8995_resume(struct snd_soc_codec *codec)
-{
-	wm8995_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-	return 0;
-}
-#else
-#define wm8995_suspend NULL
-#define wm8995_resume NULL
-#endif
-
 static int wm8995_remove(struct snd_soc_codec *codec)
 {
 	struct wm8995_priv *wm8995;
@@ -2220,8 +2203,6 @@
 static struct snd_soc_codec_driver soc_codec_dev_wm8995 = {
 	.probe = wm8995_probe,
 	.remove = wm8995_remove,
-	.suspend = wm8995_suspend,
-	.resume = wm8995_resume,
 	.set_bias_level = wm8995_set_bias_level,
 	.idle_bias_off = true,
 };
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index f16ff4f..b1dcc11 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -2216,11 +2216,7 @@
 
 static void wm8996_free_gpio(struct wm8996_priv *wm8996)
 {
-	int ret;
-
-	ret = gpiochip_remove(&wm8996->gpio_chip);
-	if (ret != 0)
-		dev_err(wm8996->dev, "Failed to remove GPIOs: %d\n", ret);
+	gpiochip_remove(&wm8996->gpio_chip);
 }
 #else
 static void wm8996_init_gpio(struct wm8996_priv *wm8996)
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
index d69510c..8e948c6 100644
--- a/sound/soc/davinci/Kconfig
+++ b/sound/soc/davinci/Kconfig
@@ -63,7 +63,8 @@
 	  Say Y if you want to add support for AIC3101 audio codec
 
 config SND_DM365_VOICE_CODEC
-	bool "Voice Codec - CQ93VC"
+	tristate "Voice Codec - CQ93VC"
+	depends on SND_DAVINCI_SOC
 	select MFD_DAVINCI_VOICECODEC
 	select SND_DAVINCI_SOC_VCIF
 	select SND_SOC_CQ0093VC
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index 68347b5..0eed9b1 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -42,14 +42,26 @@
 
 #define MCASP_MAX_AFIFO_DEPTH	64
 
+static u32 context_regs[] = {
+	DAVINCI_MCASP_TXFMCTL_REG,
+	DAVINCI_MCASP_RXFMCTL_REG,
+	DAVINCI_MCASP_TXFMT_REG,
+	DAVINCI_MCASP_RXFMT_REG,
+	DAVINCI_MCASP_ACLKXCTL_REG,
+	DAVINCI_MCASP_ACLKRCTL_REG,
+	DAVINCI_MCASP_AHCLKXCTL_REG,
+	DAVINCI_MCASP_AHCLKRCTL_REG,
+	DAVINCI_MCASP_PDIR_REG,
+	DAVINCI_MCASP_RXMASK_REG,
+	DAVINCI_MCASP_TXMASK_REG,
+	DAVINCI_MCASP_RXTDM_REG,
+	DAVINCI_MCASP_TXTDM_REG,
+};
+
 struct davinci_mcasp_context {
-	u32	txfmtctl;
-	u32	rxfmtctl;
-	u32	txfmt;
-	u32	rxfmt;
-	u32	aclkxctl;
-	u32	aclkrctl;
-	u32	pdir;
+	u32	config_regs[ARRAY_SIZE(context_regs)];
+	u32	afifo_regs[2]; /* for read/write fifo control registers */
+	u32	*xrsr_regs; /* for serializer configuration */
 };
 
 struct davinci_mcasp {
@@ -874,14 +886,24 @@
 {
 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
 	struct davinci_mcasp_context *context = &mcasp->context;
+	u32 reg;
+	int i;
 
-	context->txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG);
-	context->rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG);
-	context->txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG);
-	context->rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG);
-	context->aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG);
-	context->aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG);
-	context->pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG);
+	for (i = 0; i < ARRAY_SIZE(context_regs); i++)
+		context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]);
+
+	if (mcasp->txnumevt) {
+		reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+		context->afifo_regs[0] = mcasp_get_reg(mcasp, reg);
+	}
+	if (mcasp->rxnumevt) {
+		reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+		context->afifo_regs[1] = mcasp_get_reg(mcasp, reg);
+	}
+
+	for (i = 0; i < mcasp->num_serializer; i++)
+		context->xrsr_regs[i] = mcasp_get_reg(mcasp,
+						DAVINCI_MCASP_XRSRCTL_REG(i));
 
 	return 0;
 }
@@ -890,14 +912,24 @@
 {
 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
 	struct davinci_mcasp_context *context = &mcasp->context;
+	u32 reg;
+	int i;
 
-	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, context->txfmtctl);
-	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, context->rxfmtctl);
-	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, context->txfmt);
-	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, context->rxfmt);
-	mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, context->aclkxctl);
-	mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, context->aclkrctl);
-	mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, context->pdir);
+	for (i = 0; i < ARRAY_SIZE(context_regs); i++)
+		mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]);
+
+	if (mcasp->txnumevt) {
+		reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+		mcasp_set_reg(mcasp, reg, context->afifo_regs[0]);
+	}
+	if (mcasp->rxnumevt) {
+		reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+		mcasp_set_reg(mcasp, reg, context->afifo_regs[1]);
+	}
+
+	for (i = 0; i < mcasp->num_serializer; i++)
+		mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
+			      context->xrsr_regs[i]);
 
 	return 0;
 }
@@ -1216,6 +1248,11 @@
 	mcasp->op_mode = pdata->op_mode;
 	mcasp->tdm_slots = pdata->tdm_slots;
 	mcasp->num_serializer = pdata->num_serializer;
+#ifdef CONFIG_PM_SLEEP
+	mcasp->context.xrsr_regs = devm_kzalloc(&pdev->dev,
+					sizeof(u32) * mcasp->num_serializer,
+					GFP_KERNEL);
+#endif
 	mcasp->serial_dir = pdata->serial_dir;
 	mcasp->version = pdata->version;
 	mcasp->txnumevt = pdata->txnumevt;
diff --git a/sound/soc/davinci/edma-pcm.c b/sound/soc/davinci/edma-pcm.c
index 605e643..59e588a 100644
--- a/sound/soc/davinci/edma-pcm.c
+++ b/sound/soc/davinci/edma-pcm.c
@@ -25,6 +25,8 @@
 #include <sound/dmaengine_pcm.h>
 #include <linux/edma.h>
 
+#include "edma-pcm.h"
+
 static const struct snd_pcm_hardware edma_pcm_hardware = {
 	.info			= SNDRV_PCM_INFO_MMAP |
 				  SNDRV_PCM_INFO_MMAP_VALID |
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index f3012b6..081e406 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -240,6 +240,18 @@
 	  Say Y if you want to add support for SoC audio on an i.MX board with
 	  a wm8962 codec.
 
+config SND_SOC_IMX_ES8328
+	tristate "SoC Audio support for i.MX boards with the ES8328 codec"
+	depends on OF && (I2C || SPI)
+	select SND_SOC_ES8328_I2C if I2C
+	select SND_SOC_ES8328_SPI if SPI_MASTER
+	select SND_SOC_IMX_PCM_DMA
+	select SND_SOC_IMX_AUDMUX
+	select SND_SOC_FSL_SSI
+	help
+	  Say Y if you want to add support for the ES8328 audio codec connected
+	  via SSI/I2S over either SPI or I2C.
+
 config SND_SOC_IMX_SGTL5000
 	tristate "SoC Audio support for i.MX boards with sgtl5000"
 	depends on OF && I2C
@@ -268,6 +280,20 @@
 	select SND_SOC_MC13783
 	select SND_SOC_IMX_PCM_DMA
 
+config SND_SOC_FSL_ASOC_CARD
+	tristate "Generic ASoC Sound Card with ASRC support"
+	depends on OF && I2C
+	select SND_SOC_IMX_AUDMUX
+	select SND_SOC_IMX_PCM_DMA
+	select SND_SOC_FSL_ESAI
+	select SND_SOC_FSL_SAI
+	select SND_SOC_FSL_SSI
+	help
+	 ALSA SoC Audio support with ASRC feature for Freescale SoCs that have
+	 ESAI/SAI/SSI and connect with external CODECs such as WM8962, CS42888
+	 and SGTL5000.
+	 Say Y if you want to add support for Freescale Generic ASoC Sound Card.
+
 endif # SND_IMX_SOC
 
 endmenu
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 9ff5926..d28dc25 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -11,6 +11,7 @@
 obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o
 
 # Freescale SSI/DMA/SAI/SPDIF Support
+snd-soc-fsl-asoc-card-objs := fsl-asoc-card.o
 snd-soc-fsl-asrc-objs := fsl_asrc.o fsl_asrc_dma.o
 snd-soc-fsl-sai-objs := fsl_sai.o
 snd-soc-fsl-ssi-y := fsl_ssi.o
@@ -19,6 +20,7 @@
 snd-soc-fsl-esai-objs := fsl_esai.o
 snd-soc-fsl-utils-objs := fsl_utils.o
 snd-soc-fsl-dma-objs := fsl_dma.o
+obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o
 obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o
 obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o
 obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
@@ -50,6 +52,7 @@
 snd-soc-phycore-ac97-objs := phycore-ac97.o
 snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
 snd-soc-wm1133-ev1-objs := wm1133-ev1.o
+snd-soc-imx-es8328-objs := imx-es8328.o
 snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
 snd-soc-imx-wm8962-objs := imx-wm8962.o
 snd-soc-imx-spdif-objs := imx-spdif.o
@@ -59,6 +62,7 @@
 obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
 obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
 obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
+obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o
 obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
 obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o
 obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
new file mode 100644
index 0000000..007c772
--- /dev/null
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -0,0 +1,574 @@
+/*
+ * Freescale Generic ASoC Sound Card driver with ASRC
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <nicoleotsuka@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "fsl_esai.h"
+#include "fsl_sai.h"
+#include "imx-audmux.h"
+
+#include "../codecs/sgtl5000.h"
+#include "../codecs/wm8962.h"
+
+#define RX 0
+#define TX 1
+
+/* Default DAI format without Master and Slave flag */
+#define DAI_FMT_BASE (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF)
+
+/**
+ * CODEC private data
+ *
+ * @mclk_freq: Clock rate of MCLK
+ * @mclk_id: MCLK (or main clock) id for set_sysclk()
+ * @fll_id: FLL (or secordary clock) id for set_sysclk()
+ * @pll_id: PLL id for set_pll()
+ */
+struct codec_priv {
+	unsigned long mclk_freq;
+	u32 mclk_id;
+	u32 fll_id;
+	u32 pll_id;
+};
+
+/**
+ * CPU private data
+ *
+ * @sysclk_freq[2]: SYSCLK rates for set_sysclk()
+ * @sysclk_dir[2]: SYSCLK directions for set_sysclk()
+ * @sysclk_id[2]: SYSCLK ids for set_sysclk()
+ *
+ * Note: [1] for tx and [0] for rx
+ */
+struct cpu_priv {
+	unsigned long sysclk_freq[2];
+	u32 sysclk_dir[2];
+	u32 sysclk_id[2];
+};
+
+/**
+ * Freescale Generic ASOC card private data
+ *
+ * @dai_link[3]: DAI link structure including normal one and DPCM link
+ * @pdev: platform device pointer
+ * @codec_priv: CODEC private data
+ * @cpu_priv: CPU private data
+ * @card: ASoC card structure
+ * @sample_rate: Current sample rate
+ * @sample_format: Current sample format
+ * @asrc_rate: ASRC sample rate used by Back-Ends
+ * @asrc_format: ASRC sample format used by Back-Ends
+ * @dai_fmt: DAI format between CPU and CODEC
+ * @name: Card name
+ */
+
+struct fsl_asoc_card_priv {
+	struct snd_soc_dai_link dai_link[3];
+	struct platform_device *pdev;
+	struct codec_priv codec_priv;
+	struct cpu_priv cpu_priv;
+	struct snd_soc_card card;
+	u32 sample_rate;
+	u32 sample_format;
+	u32 asrc_rate;
+	u32 asrc_format;
+	u32 dai_fmt;
+	char name[32];
+};
+
+/**
+ * This dapm route map exsits for DPCM link only.
+ * The other routes shall go through Device Tree.
+ */
+static const struct snd_soc_dapm_route audio_map[] = {
+	{"CPU-Playback",  NULL, "ASRC-Playback"},
+	{"Playback",  NULL, "CPU-Playback"},
+	{"ASRC-Capture",  NULL, "CPU-Capture"},
+	{"CPU-Capture",  NULL, "Capture"},
+};
+
+/* Add all possible widgets into here without being redundant */
+static const struct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = {
+	SND_SOC_DAPM_LINE("Line Out Jack", NULL),
+	SND_SOC_DAPM_LINE("Line In Jack", NULL),
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_SPK("Ext Spk", NULL),
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+	SND_SOC_DAPM_MIC("AMIC", NULL),
+	SND_SOC_DAPM_MIC("DMIC", NULL),
+};
+
+static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	struct cpu_priv *cpu_priv = &priv->cpu_priv;
+	struct device *dev = rtd->card->dev;
+	int ret;
+
+	priv->sample_rate = params_rate(params);
+	priv->sample_format = params_format(params);
+
+	if (priv->card.set_bias_level)
+		return 0;
+
+	/* Specific configurations of DAIs starts from here */
+	ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, cpu_priv->sysclk_id[tx],
+				     cpu_priv->sysclk_freq[tx],
+				     cpu_priv->sysclk_dir[tx]);
+	if (ret) {
+		dev_err(dev, "failed to set sysclk for cpu dai\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_ops fsl_asoc_card_ops = {
+	.hw_params = fsl_asoc_card_hw_params,
+};
+
+static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			      struct snd_pcm_hw_params *params)
+{
+	struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+	struct snd_interval *rate;
+	struct snd_mask *mask;
+
+	rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+	rate->max = rate->min = priv->asrc_rate;
+
+	mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+	snd_mask_none(mask);
+	snd_mask_set(mask, priv->asrc_format);
+
+	return 0;
+}
+
+static struct snd_soc_dai_link fsl_asoc_card_dai[] = {
+	/* Default ASoC DAI Link*/
+	{
+		.name = "HiFi",
+		.stream_name = "HiFi",
+		.ops = &fsl_asoc_card_ops,
+	},
+	/* DPCM Link between Front-End and Back-End (Optional) */
+	{
+		.name = "HiFi-ASRC-FE",
+		.stream_name = "HiFi-ASRC-FE",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		.dynamic = 1,
+	},
+	{
+		.name = "HiFi-ASRC-BE",
+		.stream_name = "HiFi-ASRC-BE",
+		.platform_name = "snd-soc-dummy",
+		.be_hw_params_fixup = be_hw_params_fixup,
+		.ops = &fsl_asoc_card_ops,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		.no_pcm = 1,
+	},
+};
+
+static int fsl_asoc_card_set_bias_level(struct snd_soc_card *card,
+					struct snd_soc_dapm_context *dapm,
+					enum snd_soc_bias_level level)
+{
+	struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
+	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+	struct codec_priv *codec_priv = &priv->codec_priv;
+	struct device *dev = card->dev;
+	unsigned int pll_out;
+	int ret;
+
+	if (dapm->dev != codec_dai->dev)
+		return 0;
+
+	switch (level) {
+	case SND_SOC_BIAS_PREPARE:
+		if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
+			break;
+
+		if (priv->sample_format == SNDRV_PCM_FORMAT_S24_LE)
+			pll_out = priv->sample_rate * 384;
+		else
+			pll_out = priv->sample_rate * 256;
+
+		ret = snd_soc_dai_set_pll(codec_dai, codec_priv->pll_id,
+					  codec_priv->mclk_id,
+					  codec_priv->mclk_freq, pll_out);
+		if (ret) {
+			dev_err(dev, "failed to start FLL: %d\n", ret);
+			return ret;
+		}
+
+		ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->fll_id,
+					     pll_out, SND_SOC_CLOCK_IN);
+		if (ret) {
+			dev_err(dev, "failed to set SYSCLK: %d\n", ret);
+			return ret;
+		}
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (dapm->bias_level != SND_SOC_BIAS_PREPARE)
+			break;
+
+		ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
+					     codec_priv->mclk_freq,
+					     SND_SOC_CLOCK_IN);
+		if (ret) {
+			dev_err(dev, "failed to switch away from FLL: %d\n", ret);
+			return ret;
+		}
+
+		ret = snd_soc_dai_set_pll(codec_dai, codec_priv->pll_id, 0, 0, 0);
+		if (ret) {
+			dev_err(dev, "failed to stop FLL: %d\n", ret);
+			return ret;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int fsl_asoc_card_audmux_init(struct device_node *np,
+				     struct fsl_asoc_card_priv *priv)
+{
+	struct device *dev = &priv->pdev->dev;
+	u32 int_ptcr = 0, ext_ptcr = 0;
+	int int_port, ext_port;
+	int ret;
+
+	ret = of_property_read_u32(np, "mux-int-port", &int_port);
+	if (ret) {
+		dev_err(dev, "mux-int-port missing or invalid\n");
+		return ret;
+	}
+	ret = of_property_read_u32(np, "mux-ext-port", &ext_port);
+	if (ret) {
+		dev_err(dev, "mux-ext-port missing or invalid\n");
+		return ret;
+	}
+
+	/*
+	 * The port numbering in the hardware manual starts at 1, while
+	 * the AUDMUX API expects it starts at 0.
+	 */
+	int_port--;
+	ext_port--;
+
+	/*
+	 * Use asynchronous mode (6 wires) for all cases.
+	 * If only 4 wires are needed, just set SSI into
+	 * synchronous mode and enable 4 PADs in IOMUX.
+	 */
+	switch (priv->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		int_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | ext_port) |
+			   IMX_AUDMUX_V2_PTCR_RCSEL(8 | ext_port) |
+			   IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
+			   IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
+			   IMX_AUDMUX_V2_PTCR_RFSDIR |
+			   IMX_AUDMUX_V2_PTCR_RCLKDIR |
+			   IMX_AUDMUX_V2_PTCR_TFSDIR |
+			   IMX_AUDMUX_V2_PTCR_TCLKDIR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		int_ptcr = IMX_AUDMUX_V2_PTCR_RCSEL(8 | ext_port) |
+			   IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
+			   IMX_AUDMUX_V2_PTCR_RCLKDIR |
+			   IMX_AUDMUX_V2_PTCR_TCLKDIR;
+		ext_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | int_port) |
+			   IMX_AUDMUX_V2_PTCR_TFSEL(int_port) |
+			   IMX_AUDMUX_V2_PTCR_RFSDIR |
+			   IMX_AUDMUX_V2_PTCR_TFSDIR;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		int_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | ext_port) |
+			   IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
+			   IMX_AUDMUX_V2_PTCR_RFSDIR |
+			   IMX_AUDMUX_V2_PTCR_TFSDIR;
+		ext_ptcr = IMX_AUDMUX_V2_PTCR_RCSEL(8 | int_port) |
+			   IMX_AUDMUX_V2_PTCR_TCSEL(int_port) |
+			   IMX_AUDMUX_V2_PTCR_RCLKDIR |
+			   IMX_AUDMUX_V2_PTCR_TCLKDIR;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		ext_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | int_port) |
+			   IMX_AUDMUX_V2_PTCR_RCSEL(8 | int_port) |
+			   IMX_AUDMUX_V2_PTCR_TFSEL(int_port) |
+			   IMX_AUDMUX_V2_PTCR_TCSEL(int_port) |
+			   IMX_AUDMUX_V2_PTCR_RFSDIR |
+			   IMX_AUDMUX_V2_PTCR_RCLKDIR |
+			   IMX_AUDMUX_V2_PTCR_TFSDIR |
+			   IMX_AUDMUX_V2_PTCR_TCLKDIR;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Asynchronous mode can not be set along with RCLKDIR */
+	ret = imx_audmux_v2_configure_port(int_port, 0,
+					   IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
+	if (ret) {
+		dev_err(dev, "audmux internal port setup failed\n");
+		return ret;
+	}
+
+	ret = imx_audmux_v2_configure_port(int_port, int_ptcr,
+					   IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
+	if (ret) {
+		dev_err(dev, "audmux internal port setup failed\n");
+		return ret;
+	}
+
+	ret = imx_audmux_v2_configure_port(ext_port, 0,
+					   IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
+	if (ret) {
+		dev_err(dev, "audmux external port setup failed\n");
+		return ret;
+	}
+
+	ret = imx_audmux_v2_configure_port(ext_port, ext_ptcr,
+					   IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
+	if (ret) {
+		dev_err(dev, "audmux external port setup failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
+{
+	struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
+	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+	struct codec_priv *codec_priv = &priv->codec_priv;
+	struct device *dev = card->dev;
+	int ret;
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
+				     codec_priv->mclk_freq, SND_SOC_CLOCK_IN);
+	if (ret) {
+		dev_err(dev, "failed to set sysclk in %s\n", __func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int fsl_asoc_card_probe(struct platform_device *pdev)
+{
+	struct device_node *cpu_np, *codec_np, *asrc_np;
+	struct device_node *np = pdev->dev.of_node;
+	struct platform_device *asrc_pdev = NULL;
+	struct platform_device *cpu_pdev;
+	struct fsl_asoc_card_priv *priv;
+	struct i2c_client *codec_dev;
+	struct clk *codec_clk;
+	u32 width;
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	cpu_np = of_parse_phandle(np, "audio-cpu", 0);
+	/* Give a chance to old DT binding */
+	if (!cpu_np)
+		cpu_np = of_parse_phandle(np, "ssi-controller", 0);
+	codec_np = of_parse_phandle(np, "audio-codec", 0);
+	if (!cpu_np || !codec_np) {
+		dev_err(&pdev->dev, "phandle missing or invalid\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	cpu_pdev = of_find_device_by_node(cpu_np);
+	if (!cpu_pdev) {
+		dev_err(&pdev->dev, "failed to find CPU DAI device\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	codec_dev = of_find_i2c_device_by_node(codec_np);
+	if (!codec_dev) {
+		dev_err(&pdev->dev, "failed to find codec platform device\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	asrc_np = of_parse_phandle(np, "audio-asrc", 0);
+	if (asrc_np)
+		asrc_pdev = of_find_device_by_node(asrc_np);
+
+	/* Get the MCLK rate only, and leave it controlled by CODEC drivers */
+	codec_clk = clk_get(&codec_dev->dev, NULL);
+	if (!IS_ERR(codec_clk)) {
+		priv->codec_priv.mclk_freq = clk_get_rate(codec_clk);
+		clk_put(codec_clk);
+	}
+
+	/* Default sample rate and format, will be updated in hw_params() */
+	priv->sample_rate = 44100;
+	priv->sample_format = SNDRV_PCM_FORMAT_S16_LE;
+
+	/* Assign a default DAI format, and allow each card to overwrite it */
+	priv->dai_fmt = DAI_FMT_BASE;
+
+	/* Diversify the card configurations */
+	if (of_device_is_compatible(np, "fsl,imx-audio-cs42888")) {
+		priv->card.set_bias_level = NULL;
+		priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv.mclk_freq;
+		priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq;
+		priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT;
+		priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT;
+		priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
+	} else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) {
+		priv->codec_priv.mclk_id = SGTL5000_SYSCLK;
+		priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
+	} else if (of_device_is_compatible(np, "fsl,imx-audio-wm8962")) {
+		priv->card.set_bias_level = fsl_asoc_card_set_bias_level;
+		priv->codec_priv.mclk_id = WM8962_SYSCLK_MCLK;
+		priv->codec_priv.fll_id = WM8962_SYSCLK_FLL;
+		priv->codec_priv.pll_id = WM8962_FLL;
+		priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
+	} else {
+		dev_err(&pdev->dev, "unknown Device Tree compatible\n");
+		return -EINVAL;
+	}
+
+	/* Common settings for corresponding Freescale CPU DAI driver */
+	if (strstr(cpu_np->name, "ssi")) {
+		/* Only SSI needs to configure AUDMUX */
+		ret = fsl_asoc_card_audmux_init(np, priv);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to init audmux\n");
+			goto asrc_fail;
+		}
+	} else if (strstr(cpu_np->name, "esai")) {
+		priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL;
+		priv->cpu_priv.sysclk_id[0] = ESAI_HCKR_EXTAL;
+	} else if (strstr(cpu_np->name, "sai")) {
+		priv->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1;
+		priv->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1;
+	}
+
+	sprintf(priv->name, "%s-audio", codec_dev->name);
+
+	/* Initialize sound card */
+	priv->pdev = pdev;
+	priv->card.dev = &pdev->dev;
+	priv->card.name = priv->name;
+	priv->card.dai_link = priv->dai_link;
+	priv->card.dapm_routes = audio_map;
+	priv->card.late_probe = fsl_asoc_card_late_probe;
+	priv->card.num_dapm_routes = ARRAY_SIZE(audio_map);
+	priv->card.dapm_widgets = fsl_asoc_card_dapm_widgets;
+	priv->card.num_dapm_widgets = ARRAY_SIZE(fsl_asoc_card_dapm_widgets);
+
+	memcpy(priv->dai_link, fsl_asoc_card_dai,
+	       sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link));
+
+	/* Normal DAI Link */
+	priv->dai_link[0].cpu_of_node = cpu_np;
+	priv->dai_link[0].codec_of_node = codec_np;
+	priv->dai_link[0].codec_dai_name = codec_dev->name;
+	priv->dai_link[0].platform_of_node = cpu_np;
+	priv->dai_link[0].dai_fmt = priv->dai_fmt;
+	priv->card.num_links = 1;
+
+	if (asrc_pdev) {
+		/* DPCM DAI Links only if ASRC exsits */
+		priv->dai_link[1].cpu_of_node = asrc_np;
+		priv->dai_link[1].platform_of_node = asrc_np;
+		priv->dai_link[2].codec_dai_name = codec_dev->name;
+		priv->dai_link[2].codec_of_node = codec_np;
+		priv->dai_link[2].cpu_of_node = cpu_np;
+		priv->dai_link[2].dai_fmt = priv->dai_fmt;
+		priv->card.num_links = 3;
+
+		ret = of_property_read_u32(asrc_np, "fsl,asrc-rate",
+					   &priv->asrc_rate);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to get output rate\n");
+			ret = -EINVAL;
+			goto asrc_fail;
+		}
+
+		ret = of_property_read_u32(asrc_np, "fsl,asrc-width", &width);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to get output rate\n");
+			ret = -EINVAL;
+			goto asrc_fail;
+		}
+
+		if (width == 24)
+			priv->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
+		else
+			priv->asrc_format = SNDRV_PCM_FORMAT_S16_LE;
+	}
+
+	/* Finish card registering */
+	platform_set_drvdata(pdev, priv);
+	snd_soc_card_set_drvdata(&priv->card, priv);
+
+	ret = devm_snd_soc_register_card(&pdev->dev, &priv->card);
+	if (ret)
+		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+
+asrc_fail:
+	of_node_put(asrc_np);
+fail:
+	of_node_put(codec_np);
+	of_node_put(cpu_np);
+
+	return ret;
+}
+
+static const struct of_device_id fsl_asoc_card_dt_ids[] = {
+	{ .compatible = "fsl,imx-audio-cs42888", },
+	{ .compatible = "fsl,imx-audio-sgtl5000", },
+	{ .compatible = "fsl,imx-audio-wm8962", },
+	{}
+};
+
+static struct platform_driver fsl_asoc_card_driver = {
+	.probe = fsl_asoc_card_probe,
+	.driver = {
+		.name = "fsl-asoc-card",
+		.pm = &snd_soc_pm_ops,
+		.of_match_table = fsl_asoc_card_dt_ids,
+	},
+};
+module_platform_driver(fsl_asoc_card_driver);
+
+MODULE_DESCRIPTION("Freescale Generic ASoC Sound Card driver with ASRC");
+MODULE_AUTHOR("Nicolin Chen <nicoleotsuka@gmail.com>");
+MODULE_ALIAS("platform:fsl-asoc-card");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index 8221104..3b14531 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -684,7 +684,7 @@
 	}
 }
 
-static struct regmap_config fsl_asrc_regmap_config = {
+static const struct regmap_config fsl_asrc_regmap_config = {
 	.reg_bits = 32,
 	.reg_stride = 4,
 	.val_bits = 32,
@@ -802,10 +802,6 @@
 
 	asrc_priv->paddr = res->start;
 
-	/* Register regmap and let it prepare core clock */
-	if (of_property_read_bool(np, "big-endian"))
-		fsl_asrc_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
-
 	asrc_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs,
 						      &fsl_asrc_regmap_config);
 	if (IS_ERR(asrc_priv->regmap)) {
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index a3b29ed..8bcdfda 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -37,6 +37,7 @@
  * @fsysclk: system clock source to derive HCK, SCK and FS
  * @fifo_depth: depth of tx/rx FIFO
  * @slot_width: width of each DAI slot
+ * @slots: number of slots
  * @hck_rate: clock rate of desired HCKx clock
  * @sck_rate: clock rate of desired SCKx clock
  * @hck_dir: the direction of HCKx pads
@@ -55,6 +56,7 @@
 	struct clk *fsysclk;
 	u32 fifo_depth;
 	u32 slot_width;
+	u32 slots;
 	u32 hck_rate[2];
 	u32 sck_rate[2];
 	bool hck_dir[2];
@@ -362,6 +364,7 @@
 			   ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask));
 
 	esai_priv->slot_width = slot_width;
+	esai_priv->slots = slots;
 
 	return 0;
 }
@@ -509,10 +512,11 @@
 	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 	u32 width = snd_pcm_format_width(params_format(params));
 	u32 channels = params_channels(params);
+	u32 pins = DIV_ROUND_UP(channels, esai_priv->slots);
 	u32 bclk, mask, val;
 	int ret;
 
-	bclk = params_rate(params) * esai_priv->slot_width * 2;
+	bclk = params_rate(params) * esai_priv->slot_width * esai_priv->slots;
 
 	ret = fsl_esai_set_bclk(dai, tx, bclk);
 	if (ret)
@@ -529,7 +533,7 @@
 	mask = ESAI_xFCR_xFR_MASK | ESAI_xFCR_xWA_MASK | ESAI_xFCR_xFWM_MASK |
 	      (tx ? ESAI_xFCR_TE_MASK | ESAI_xFCR_TIEN : ESAI_xFCR_RE_MASK);
 	val = ESAI_xFCR_xWA(width) | ESAI_xFCR_xFWM(esai_priv->fifo_depth) |
-	     (tx ? ESAI_xFCR_TE(channels) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(channels));
+	     (tx ? ESAI_xFCR_TE(pins) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(pins));
 
 	regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val);
 
@@ -564,6 +568,7 @@
 	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
 	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 	u8 i, channels = substream->runtime->channels;
+	u32 pins = DIV_ROUND_UP(channels, esai_priv->slots);
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
@@ -578,7 +583,7 @@
 
 		regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
 				   tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK,
-				   tx ? ESAI_xCR_TE(channels) : ESAI_xCR_RE(channels));
+				   tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins));
 		break;
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_STOP:
@@ -705,7 +710,7 @@
 	}
 }
 
-static struct regmap_config fsl_esai_regmap_config = {
+static const struct regmap_config fsl_esai_regmap_config = {
 	.reg_bits = 32,
 	.reg_stride = 4,
 	.val_bits = 32,
@@ -731,9 +736,6 @@
 	esai_priv->pdev = pdev;
 	strcpy(esai_priv->name, np->name);
 
-	if (of_property_read_bool(np, "big-endian"))
-		fsl_esai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
-
 	/* Get the addresses and IRQ */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	regs = devm_ioremap_resource(&pdev->dev, res);
@@ -781,6 +783,9 @@
 	/* Set a default slot size */
 	esai_priv->slot_width = 32;
 
+	/* Set a default slot number */
+	esai_priv->slots = 2;
+
 	/* Set a default master/slave state */
 	esai_priv->slave_mode = true;
 
diff --git a/sound/soc/fsl/fsl_esai.h b/sound/soc/fsl/fsl_esai.h
index 75e1403..91a550f 100644
--- a/sound/soc/fsl/fsl_esai.h
+++ b/sound/soc/fsl/fsl_esai.h
@@ -130,8 +130,8 @@
 #define ESAI_xFCR_RE_WIDTH	4
 #define ESAI_xFCR_TE_MASK	(((1 << ESAI_xFCR_TE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT)
 #define ESAI_xFCR_RE_MASK	(((1 << ESAI_xFCR_RE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT)
-#define ESAI_xFCR_TE(x) 	((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_TE_MASK)
-#define ESAI_xFCR_RE(x) 	((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_RE_MASK)
+#define ESAI_xFCR_TE(x) 	((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - x)) & ESAI_xFCR_TE_MASK)
+#define ESAI_xFCR_RE(x) 	((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - x)) & ESAI_xFCR_RE_MASK)
 #define ESAI_xFCR_xFR_SHIFT	1
 #define ESAI_xFCR_xFR_MASK	(1 << ESAI_xFCR_xFR_SHIFT)
 #define ESAI_xFCR_xFR		(1 << ESAI_xFCR_xFR_SHIFT)
@@ -272,8 +272,8 @@
 #define ESAI_xCR_RE_WIDTH	4
 #define ESAI_xCR_TE_MASK	(((1 << ESAI_xCR_TE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT)
 #define ESAI_xCR_RE_MASK	(((1 << ESAI_xCR_RE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT)
-#define ESAI_xCR_TE(x) 		((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_TE_MASK)
-#define ESAI_xCR_RE(x) 		((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_RE_MASK)
+#define ESAI_xCR_TE(x) 		((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - x)) & ESAI_xCR_TE_MASK)
+#define ESAI_xCR_RE(x) 		((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - x)) & ESAI_xCR_RE_MASK)
 
 /*
  * Transmit Clock Control Register -- REG_ESAI_TCCR 0xD8
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index faa0497..7eeb1dd 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -175,7 +175,7 @@
 	bool tx = fsl_dir == FSL_FMT_TRANSMITTER;
 	u32 val_cr2 = 0, val_cr4 = 0;
 
-	if (!sai->big_endian_data)
+	if (!sai->is_lsb_first)
 		val_cr4 |= FSL_SAI_CR4_MF;
 
 	/* DAI mode */
@@ -304,7 +304,7 @@
 	val_cr5 |= FSL_SAI_CR5_WNW(word_width);
 	val_cr5 |= FSL_SAI_CR5_W0W(word_width);
 
-	if (sai->big_endian_data)
+	if (sai->is_lsb_first)
 		val_cr5 |= FSL_SAI_CR5_FBT(0);
 	else
 		val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
@@ -330,13 +330,13 @@
 	u32 xcsr, count = 100;
 
 	/*
-	 * The transmitter bit clock and frame sync are to be
-	 * used by both the transmitter and receiver.
+	 * Asynchronous mode: Clear SYNC for both Tx and Rx.
+	 * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx.
+	 * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx.
 	 */
-	regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC,
-			   ~FSL_SAI_CR2_SYNC);
+	regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, 0);
 	regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC,
-			   FSL_SAI_CR2_SYNC);
+			   sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0);
 
 	/*
 	 * It is recommended that the transmitter is the last enabled
@@ -437,8 +437,13 @@
 {
 	struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
 
-	regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0);
-	regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0);
+	/* Software Reset for both Tx and Rx */
+	regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR);
+	regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR);
+	/* Clear SR bit to finish the reset */
+	regmap_write(sai->regmap, FSL_SAI_TCSR, 0);
+	regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
+
 	regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
 			   FSL_SAI_MAXBURST_TX * 2);
 	regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
@@ -539,7 +544,7 @@
 	}
 }
 
-static struct regmap_config fsl_sai_regmap_config = {
+static const struct regmap_config fsl_sai_regmap_config = {
 	.reg_bits = 32,
 	.reg_stride = 4,
 	.val_bits = 32,
@@ -568,11 +573,7 @@
 	if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai"))
 		sai->sai_on_imx = true;
 
-	sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
-	if (sai->big_endian_regs)
-		fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
-
-	sai->big_endian_data = of_property_read_bool(np, "big-endian-data");
+	sai->is_lsb_first = of_property_read_bool(np, "lsb-first");
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	base = devm_ioremap_resource(&pdev->dev, res);
@@ -621,6 +622,33 @@
 		return ret;
 	}
 
+	/* Sync Tx with Rx as default by following old DT binding */
+	sai->synchronous[RX] = true;
+	sai->synchronous[TX] = false;
+	fsl_sai_dai.symmetric_rates = 1;
+	fsl_sai_dai.symmetric_channels = 1;
+	fsl_sai_dai.symmetric_samplebits = 1;
+
+	if (of_find_property(np, "fsl,sai-synchronous-rx", NULL) &&
+	    of_find_property(np, "fsl,sai-asynchronous", NULL)) {
+		/* error out if both synchronous and asynchronous are present */
+		dev_err(&pdev->dev, "invalid binding for synchronous mode\n");
+		return -EINVAL;
+	}
+
+	if (of_find_property(np, "fsl,sai-synchronous-rx", NULL)) {
+		/* Sync Rx with Tx */
+		sai->synchronous[RX] = false;
+		sai->synchronous[TX] = true;
+	} else if (of_find_property(np, "fsl,sai-asynchronous", NULL)) {
+		/* Discard all settings for asynchronous mode */
+		sai->synchronous[RX] = false;
+		sai->synchronous[TX] = false;
+		fsl_sai_dai.symmetric_rates = 0;
+		fsl_sai_dai.symmetric_channels = 0;
+		fsl_sai_dai.symmetric_samplebits = 0;
+	}
+
 	sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
 	sai->dma_params_tx.addr = res->start + FSL_SAI_TDR;
 	sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
index 0e6c9f5..3466720 100644
--- a/sound/soc/fsl/fsl_sai.h
+++ b/sound/soc/fsl/fsl_sai.h
@@ -48,6 +48,7 @@
 /* SAI Transmit/Recieve Control Register */
 #define FSL_SAI_CSR_TERE	BIT(31)
 #define FSL_SAI_CSR_FR		BIT(25)
+#define FSL_SAI_CSR_SR		BIT(24)
 #define FSL_SAI_CSR_xF_SHIFT	16
 #define FSL_SAI_CSR_xF_W_SHIFT	18
 #define FSL_SAI_CSR_xF_MASK	(0x1f << FSL_SAI_CSR_xF_SHIFT)
@@ -131,13 +132,16 @@
 	struct clk *bus_clk;
 	struct clk *mclk_clk[FSL_SAI_MCLK_MAX];
 
-	bool big_endian_regs;
-	bool big_endian_data;
+	bool is_lsb_first;
 	bool is_dsp_mode;
 	bool sai_on_imx;
+	bool synchronous[2];
 
 	struct snd_dmaengine_dai_dma_data dma_params_rx;
 	struct snd_dmaengine_dai_dma_data dma_params_tx;
 };
 
+#define TX 1
+#define RX 0
+
 #endif /* __FSL_SAI_H */
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 70acfe4..9b79162 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -15,7 +15,6 @@
 
 #include <linux/bitrev.h>
 #include <linux/clk.h>
-#include <linux/clk-private.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
@@ -1040,7 +1039,7 @@
 	}
 }
 
-static struct regmap_config fsl_spdif_regmap_config = {
+static const struct regmap_config fsl_spdif_regmap_config = {
 	.reg_bits = 32,
 	.reg_stride = 4,
 	.val_bits = 32,
@@ -1184,9 +1183,6 @@
 	memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai));
 	spdif_priv->cpu_dai_drv.name = spdif_priv->name;
 
-	if (of_property_read_bool(np, "big-endian"))
-		fsl_spdif_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
-
 	/* Get the addresses and IRQ */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	regs = devm_ioremap_resource(&pdev->dev, res);
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index de6ab06..e695517 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -169,6 +169,7 @@
 	u8 i2s_mode;
 	bool use_dma;
 	bool use_dual_fifo;
+	bool has_ipg_clk_name;
 	unsigned int fifo_depth;
 	struct fsl_ssi_rxtx_reg_val rxtx_reg_val;
 
@@ -259,6 +260,11 @@
 		SND_SOC_DAIFMT_CBS_CFS;
 }
 
+static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi_private *ssi_private)
+{
+	return (ssi_private->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
+		SND_SOC_DAIFMT_CBM_CFS;
+}
 /**
  * fsl_ssi_isr: SSI interrupt handler
  *
@@ -525,6 +531,11 @@
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct fsl_ssi_private *ssi_private =
 		snd_soc_dai_get_drvdata(rtd->cpu_dai);
+	int ret;
+
+	ret = clk_prepare_enable(ssi_private->clk);
+	if (ret)
+		return ret;
 
 	/* When using dual fifo mode, it is safer to ensure an even period
 	 * size. If appearing to an odd number while DMA always starts its
@@ -539,6 +550,21 @@
 }
 
 /**
+ * fsl_ssi_shutdown: shutdown the SSI
+ *
+ */
+static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct fsl_ssi_private *ssi_private =
+		snd_soc_dai_get_drvdata(rtd->cpu_dai);
+
+	clk_disable_unprepare(ssi_private->clk);
+
+}
+
+/**
  * fsl_ssi_set_bclk - configure Digital Audio Interface bit clock
  *
  * Note: This function can be only called when using SSI as DAI master
@@ -705,6 +731,23 @@
 		}
 	}
 
+	if (!fsl_ssi_is_ac97(ssi_private)) {
+		u8 i2smode;
+		/*
+		 * Switch to normal net mode in order to have a frame sync
+		 * signal every 32 bits instead of 16 bits
+		 */
+		if (fsl_ssi_is_i2s_cbm_cfs(ssi_private) && sample_size == 16)
+			i2smode = CCSR_SSI_SCR_I2S_MODE_NORMAL |
+				CCSR_SSI_SCR_NET;
+		else
+			i2smode = ssi_private->i2s_mode;
+
+		regmap_update_bits(regs, CCSR_SSI_SCR,
+				CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK,
+				channels == 1 ? 0 : i2smode);
+	}
+
 	/*
 	 * FIXME: The documentation says that SxCCR[WL] should not be
 	 * modified while the SSI is enabled.  The only time this can
@@ -724,11 +767,6 @@
 		regmap_update_bits(regs, CCSR_SSI_SRCCR, CCSR_SSI_SxCCR_WL_MASK,
 				wl);
 
-	if (!fsl_ssi_is_ac97(ssi_private))
-		regmap_update_bits(regs, CCSR_SSI_SCR,
-				CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK,
-				channels == 1 ? 0 : ssi_private->i2s_mode);
-
 	return 0;
 }
 
@@ -781,6 +819,7 @@
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
 		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+		case SND_SOC_DAIFMT_CBM_CFS:
 		case SND_SOC_DAIFMT_CBS_CFS:
 			ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_MASTER;
 			regmap_update_bits(regs, CCSR_SSI_STCCR,
@@ -854,6 +893,11 @@
 	case SND_SOC_DAIFMT_CBM_CFM:
 		scr &= ~CCSR_SSI_SCR_SYS_CLK_EN;
 		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		strcr &= ~CCSR_SSI_STCR_TXDIR;
+		strcr |= CCSR_SSI_STCR_TFDIR;
+		scr &= ~CCSR_SSI_SCR_SYS_CLK_EN;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -1021,6 +1065,7 @@
 
 static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
 	.startup	= fsl_ssi_startup,
+	.shutdown       = fsl_ssi_shutdown,
 	.hw_params	= fsl_ssi_hw_params,
 	.hw_free	= fsl_ssi_hw_free,
 	.set_fmt	= fsl_ssi_set_dai_fmt,
@@ -1146,17 +1191,22 @@
 	u32 dmas[4];
 	int ret;
 
-	ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
+	if (ssi_private->has_ipg_clk_name)
+		ssi_private->clk = devm_clk_get(&pdev->dev, "ipg");
+	else
+		ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(ssi_private->clk)) {
 		ret = PTR_ERR(ssi_private->clk);
 		dev_err(&pdev->dev, "could not get clock: %d\n", ret);
 		return ret;
 	}
 
-	ret = clk_prepare_enable(ssi_private->clk);
-	if (ret) {
-		dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
-		return ret;
+	if (!ssi_private->has_ipg_clk_name) {
+		ret = clk_prepare_enable(ssi_private->clk);
+		if (ret) {
+			dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
+			return ret;
+		}
 	}
 
 	/* For those SLAVE implementations, we ingore non-baudclk cases
@@ -1214,8 +1264,9 @@
 	return 0;
 
 error_pcm:
-	clk_disable_unprepare(ssi_private->clk);
 
+	if (!ssi_private->has_ipg_clk_name)
+		clk_disable_unprepare(ssi_private->clk);
 	return ret;
 }
 
@@ -1224,7 +1275,8 @@
 {
 	if (!ssi_private->use_dma)
 		imx_pcm_fiq_exit(pdev);
-	clk_disable_unprepare(ssi_private->clk);
+	if (!ssi_private->has_ipg_clk_name)
+		clk_disable_unprepare(ssi_private->clk);
 }
 
 static int fsl_ssi_probe(struct platform_device *pdev)
@@ -1263,9 +1315,6 @@
 	if (sprop) {
 		if (!strcmp(sprop, "ac97-slave"))
 			ssi_private->dai_fmt = SND_SOC_DAIFMT_AC97;
-		else if (!strcmp(sprop, "i2s-slave"))
-			ssi_private->dai_fmt = SND_SOC_DAIFMT_I2S |
-				SND_SOC_DAIFMT_CBM_CFM;
 	}
 
 	ssi_private->use_dma = !of_property_read_bool(np,
@@ -1299,8 +1348,16 @@
 		return -ENOMEM;
 	}
 
-	ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem,
+	ret = of_property_match_string(np, "clock-names", "ipg");
+	if (ret < 0) {
+		ssi_private->has_ipg_clk_name = false;
+		ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem,
 			&fsl_ssi_regconfig);
+	} else {
+		ssi_private->has_ipg_clk_name = true;
+		ssi_private->regs = devm_regmap_init_mmio_clk(&pdev->dev,
+			"ipg", iomem, &fsl_ssi_regconfig);
+	}
 	if (IS_ERR(ssi_private->regs)) {
 		dev_err(&pdev->dev, "Failed to init register map\n");
 		return PTR_ERR(ssi_private->regs);
diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c
new file mode 100644
index 0000000..f8cf10e
--- /dev/null
+++ b/sound/soc/fsl/imx-es8328.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2012 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/i2c.h>
+#include <linux/of_gpio.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+#include "imx-audmux.h"
+
+#define DAI_NAME_SIZE	32
+#define MUX_PORT_MAX	7
+
+struct imx_es8328_data {
+	struct device *dev;
+	struct snd_soc_dai_link dai;
+	struct snd_soc_card card;
+	char codec_dai_name[DAI_NAME_SIZE];
+	char platform_name[DAI_NAME_SIZE];
+	int jack_gpio;
+};
+
+static struct snd_soc_jack_gpio headset_jack_gpios[] = {
+	{
+		.gpio = -1,
+		.name = "headset-gpio",
+		.report = SND_JACK_HEADSET,
+		.invert = 0,
+		.debounce_time = 200,
+	},
+};
+
+static struct snd_soc_jack headset_jack;
+
+static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct imx_es8328_data *data = container_of(rtd->card,
+					struct imx_es8328_data, card);
+	int ret = 0;
+
+	/* Headphone jack detection */
+	if (gpio_is_valid(data->jack_gpio)) {
+		ret = snd_soc_jack_new(rtd->codec, "Headphone",
+				       SND_JACK_HEADPHONE | SND_JACK_BTN_0,
+				       &headset_jack);
+		if (ret)
+			return ret;
+
+		headset_jack_gpios[0].gpio = data->jack_gpio;
+		ret = snd_soc_jack_add_gpios(&headset_jack,
+					     ARRAY_SIZE(headset_jack_gpios),
+					     headset_jack_gpios);
+	}
+
+	return ret;
+}
+
+static const struct snd_soc_dapm_widget imx_es8328_dapm_widgets[] = {
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+	SND_SOC_DAPM_HP("Headphone", NULL),
+	SND_SOC_DAPM_SPK("Speaker", NULL),
+	SND_SOC_DAPM_REGULATOR_SUPPLY("audio-amp", 1, 0),
+};
+
+static int imx_es8328_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *ssi_np = NULL, *codec_np = NULL;
+	struct platform_device *ssi_pdev;
+	struct imx_es8328_data *data;
+	u32 int_port, ext_port;
+	int ret;
+	struct device *dev = &pdev->dev;
+
+	ret = of_property_read_u32(np, "mux-int-port", &int_port);
+	if (ret) {
+		dev_err(dev, "mux-int-port missing or invalid\n");
+		goto fail;
+	}
+	if (int_port > MUX_PORT_MAX || int_port == 0) {
+		dev_err(dev, "mux-int-port: hardware only has %d mux ports\n",
+			MUX_PORT_MAX);
+		goto fail;
+	}
+
+	ret = of_property_read_u32(np, "mux-ext-port", &ext_port);
+	if (ret) {
+		dev_err(dev, "mux-ext-port missing or invalid\n");
+		goto fail;
+	}
+	if (ext_port > MUX_PORT_MAX || ext_port == 0) {
+		dev_err(dev, "mux-ext-port: hardware only has %d mux ports\n",
+			MUX_PORT_MAX);
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	/*
+	 * The port numbering in the hardware manual starts at 1, while
+	 * the audmux API expects it starts at 0.
+	 */
+	int_port--;
+	ext_port--;
+	ret = imx_audmux_v2_configure_port(int_port,
+			IMX_AUDMUX_V2_PTCR_SYN |
+			IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
+			IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
+			IMX_AUDMUX_V2_PTCR_TFSDIR |
+			IMX_AUDMUX_V2_PTCR_TCLKDIR,
+			IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
+	if (ret) {
+		dev_err(dev, "audmux internal port setup failed\n");
+		return ret;
+	}
+	ret = imx_audmux_v2_configure_port(ext_port,
+			IMX_AUDMUX_V2_PTCR_SYN,
+			IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
+	if (ret) {
+		dev_err(dev, "audmux external port setup failed\n");
+		return ret;
+	}
+
+	ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0);
+	codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
+	if (!ssi_np || !codec_np) {
+		dev_err(dev, "phandle missing or invalid\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	ssi_pdev = of_find_device_by_node(ssi_np);
+	if (!ssi_pdev) {
+		dev_err(dev, "failed to find SSI platform device\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	data->dev = dev;
+
+	data->jack_gpio = of_get_named_gpio(pdev->dev.of_node, "jack-gpio", 0);
+
+	data->dai.name = "hifi";
+	data->dai.stream_name = "hifi";
+	data->dai.codec_dai_name = "es8328-hifi-analog";
+	data->dai.codec_of_node = codec_np;
+	data->dai.cpu_of_node = ssi_np;
+	data->dai.platform_of_node = ssi_np;
+	data->dai.init = &imx_es8328_dai_init;
+	data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			    SND_SOC_DAIFMT_CBM_CFM;
+
+	data->card.dev = dev;
+	data->card.dapm_widgets = imx_es8328_dapm_widgets;
+	data->card.num_dapm_widgets = ARRAY_SIZE(imx_es8328_dapm_widgets);
+	ret = snd_soc_of_parse_card_name(&data->card, "model");
+	if (ret) {
+		dev_err(dev, "Unable to parse card name\n");
+		goto fail;
+	}
+	ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing");
+	if (ret) {
+		dev_err(dev, "Unable to parse routing: %d\n", ret);
+		goto fail;
+	}
+	data->card.num_links = 1;
+	data->card.owner = THIS_MODULE;
+	data->card.dai_link = &data->dai;
+
+	ret = snd_soc_register_card(&data->card);
+	if (ret) {
+		dev_err(dev, "Unable to register: %d\n", ret);
+		goto fail;
+	}
+
+	platform_set_drvdata(pdev, data);
+fail:
+	of_node_put(ssi_np);
+	of_node_put(codec_np);
+
+	return ret;
+}
+
+static int imx_es8328_remove(struct platform_device *pdev)
+{
+	struct imx_es8328_data *data = platform_get_drvdata(pdev);
+
+	snd_soc_jack_free_gpios(&headset_jack, ARRAY_SIZE(headset_jack_gpios),
+				headset_jack_gpios);
+
+	snd_soc_unregister_card(&data->card);
+
+	return 0;
+}
+
+static const struct of_device_id imx_es8328_dt_ids[] = {
+	{ .compatible = "fsl,imx-audio-es8328", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_es8328_dt_ids);
+
+static struct platform_driver imx_es8328_driver = {
+	.driver = {
+		.name = "imx-es8328",
+		.of_match_table = imx_es8328_dt_ids,
+	},
+	.probe = imx_es8328_probe,
+	.remove = imx_es8328_remove,
+};
+module_platform_driver(imx_es8328_driver);
+
+MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
+MODULE_DESCRIPTION("Kosagi i.MX6 ES8328 ASoC machine driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:imx-audio-es8328");
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index cef7776..d1b7293 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -10,10 +10,13 @@
  */
 #include <linux/clk.h>
 #include <linux/device.h>
+#include <linux/gpio.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/string.h>
+#include <sound/jack.h>
 #include <sound/simple_card.h>
 #include <sound/soc-dai.h>
 #include <sound/soc.h>
@@ -25,9 +28,15 @@
 		struct asoc_simple_dai codec_dai;
 	} *dai_props;
 	unsigned int mclk_fs;
+	int gpio_hp_det;
+	int gpio_mic_det;
 	struct snd_soc_dai_link dai_link[];	/* dynamically allocated */
 };
 
+#define simple_priv_to_dev(priv) ((priv)->snd_card.dev)
+#define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i)
+#define simple_priv_to_props(priv, i) ((priv)->dai_props + i)
+
 static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
 				      struct snd_pcm_hw_params *params)
 {
@@ -50,6 +59,32 @@
 	.hw_params = asoc_simple_card_hw_params,
 };
 
+static struct snd_soc_jack simple_card_hp_jack;
+static struct snd_soc_jack_pin simple_card_hp_jack_pins[] = {
+	{
+		.pin = "Headphones",
+		.mask = SND_JACK_HEADPHONE,
+	},
+};
+static struct snd_soc_jack_gpio simple_card_hp_jack_gpio = {
+	.name = "Headphone detection",
+	.report = SND_JACK_HEADPHONE,
+	.debounce_time = 150,
+};
+
+static struct snd_soc_jack simple_card_mic_jack;
+static struct snd_soc_jack_pin simple_card_mic_jack_pins[] = {
+	{
+		.pin = "Mic Jack",
+		.mask = SND_JACK_MICROPHONE,
+	},
+};
+static struct snd_soc_jack_gpio simple_card_mic_jack_gpio = {
+	.name = "Mic detection",
+	.report = SND_JACK_MICROPHONE,
+	.debounce_time = 150,
+};
+
 static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
 				       struct asoc_simple_dai *set)
 {
@@ -105,42 +140,70 @@
 	if (ret < 0)
 		return ret;
 
+	if (gpio_is_valid(priv->gpio_hp_det)) {
+		snd_soc_jack_new(codec->codec, "Headphones", SND_JACK_HEADPHONE,
+				 &simple_card_hp_jack);
+		snd_soc_jack_add_pins(&simple_card_hp_jack,
+				      ARRAY_SIZE(simple_card_hp_jack_pins),
+				      simple_card_hp_jack_pins);
+
+		simple_card_hp_jack_gpio.gpio = priv->gpio_hp_det;
+		snd_soc_jack_add_gpios(&simple_card_hp_jack, 1,
+				       &simple_card_hp_jack_gpio);
+	}
+
+	if (gpio_is_valid(priv->gpio_mic_det)) {
+		snd_soc_jack_new(codec->codec, "Mic Jack", SND_JACK_MICROPHONE,
+				 &simple_card_mic_jack);
+		snd_soc_jack_add_pins(&simple_card_mic_jack,
+				      ARRAY_SIZE(simple_card_mic_jack_pins),
+				      simple_card_mic_jack_pins);
+		simple_card_mic_jack_gpio.gpio = priv->gpio_mic_det;
+		snd_soc_jack_add_gpios(&simple_card_mic_jack, 1,
+				       &simple_card_mic_jack_gpio);
+	}
 	return 0;
 }
 
 static int
 asoc_simple_card_sub_parse_of(struct device_node *np,
 			      struct asoc_simple_dai *dai,
-			      const struct device_node **p_node,
-			      const char **name)
+			      struct device_node **p_node,
+			      const char **name,
+			      int *args_count)
 {
-	struct device_node *node;
+	struct of_phandle_args args;
 	struct clk *clk;
 	u32 val;
 	int ret;
 
 	/*
-	 * get node via "sound-dai = <&phandle port>"
+	 * Get node via "sound-dai = <&phandle port>"
 	 * it will be used as xxx_of_node on soc_bind_dai_link()
 	 */
-	node = of_parse_phandle(np, "sound-dai", 0);
-	if (!node)
-		return -ENODEV;
-	*p_node = node;
+	ret = of_parse_phandle_with_args(np, "sound-dai",
+					 "#sound-dai-cells", 0, &args);
+	if (ret)
+		return ret;
 
-	/* get dai->name */
+	*p_node = args.np;
+
+	if (args_count)
+		*args_count = args.args_count;
+
+	/* Get dai->name */
 	ret = snd_soc_of_get_dai_name(np, name);
 	if (ret < 0)
 		return ret;
 
-	/* parse TDM slot */
+	/* Parse TDM slot */
 	ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width);
 	if (ret)
 		return ret;
 
 	/*
-	 * dai->sysclk come from
-	 *  "clocks = <&xxx>" (if system has common clock)
+	 * Parse dai->sysclk come from "clocks = <&xxx>"
+	 * (if system has common clock)
 	 *  or "system-clock-frequency = <xxx>"
 	 *  or device's module clock.
 	 */
@@ -155,7 +218,7 @@
 	} else if (!of_property_read_u32(np, "system-clock-frequency", &val)) {
 		dai->sysclk = val;
 	} else {
-		clk = of_clk_get(node, 0);
+		clk = of_clk_get(args.np, 0);
 		if (!IS_ERR(clk))
 			dai->sysclk = clk_get_rate(clk);
 	}
@@ -163,12 +226,14 @@
 	return 0;
 }
 
-static int simple_card_dai_link_of(struct device_node *node,
-				   struct device *dev,
-				   struct snd_soc_dai_link *dai_link,
-				   struct simple_dai_props *dai_props,
-				   bool is_top_level_node)
+static int asoc_simple_card_dai_link_of(struct device_node *node,
+					struct simple_card_data *priv,
+					int idx,
+					bool is_top_level_node)
 {
+	struct device *dev = simple_priv_to_dev(priv);
+	struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
+	struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
 	struct device_node *np = NULL;
 	struct device_node *bitclkmaster = NULL;
 	struct device_node *framemaster = NULL;
@@ -176,8 +241,9 @@
 	char *name;
 	char prop[128];
 	char *prefix = "";
-	int ret;
+	int ret, cpu_args;
 
+	/* For single DAI link & old style of DT node */
 	if (is_top_level_node)
 		prefix = "simple-audio-card,";
 
@@ -195,7 +261,8 @@
 
 	ret = asoc_simple_card_sub_parse_of(np, &dai_props->cpu_dai,
 					    &dai_link->cpu_of_node,
-					    &dai_link->cpu_dai_name);
+					    &dai_link->cpu_dai_name,
+					    &cpu_args);
 	if (ret < 0)
 		goto dai_link_of_err;
 
@@ -226,14 +293,16 @@
 
 	ret = asoc_simple_card_sub_parse_of(np, &dai_props->codec_dai,
 					    &dai_link->codec_of_node,
-					    &dai_link->codec_dai_name);
+					    &dai_link->codec_dai_name, NULL);
 	if (ret < 0)
 		goto dai_link_of_err;
 
 	if (strlen(prefix) && !bitclkmaster && !framemaster) {
-		/* No dai-link level and master setting was not found from
-		   sound node level, revert back to legacy DT parsing and
-		   take the settings from codec node. */
+		/*
+		 * No DAI link level and master setting was found
+		 * from sound node level, revert back to legacy DT
+		 * parsing and take the settings from codec node.
+		 */
 		dev_dbg(dev, "%s: Revert to legacy daifmt parsing\n",
 			__func__);
 		dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt =
@@ -262,10 +331,10 @@
 		goto dai_link_of_err;
 	}
 
-	/* simple-card assumes platform == cpu */
+	/* Simple Card assumes platform == cpu */
 	dai_link->platform_of_node = dai_link->cpu_of_node;
 
-	/* Link name is created from CPU/CODEC dai name */
+	/* DAI link name is created from CPU/CODEC dai name */
 	name = devm_kzalloc(dev,
 			    strlen(dai_link->cpu_dai_name)   +
 			    strlen(dai_link->codec_dai_name) + 2,
@@ -274,6 +343,7 @@
 				dai_link->codec_dai_name);
 	dai_link->name = dai_link->stream_name = name;
 	dai_link->ops = &asoc_simple_card_ops;
+	dai_link->init = asoc_simple_card_dai_init;
 
 	dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
 	dev_dbg(dev, "\tcpu : %s / %04x / %d\n",
@@ -285,6 +355,18 @@
 		dai_props->codec_dai.fmt,
 		dai_props->codec_dai.sysclk);
 
+	/*
+	 * In soc_bind_dai_link() will check cpu name after
+	 * of_node matching if dai_link has cpu_dai_name.
+	 * but, it will never match if name was created by
+	 * fmt_single_name() remove cpu_dai_name if cpu_args
+	 * was 0. See:
+	 *	fmt_single_name()
+	 *	fmt_multiple_name()
+	 */
+	if (!cpu_args)
+		dai_link->cpu_dai_name = NULL;
+
 dai_link_of_err:
 	if (np)
 		of_node_put(np);
@@ -296,19 +378,19 @@
 }
 
 static int asoc_simple_card_parse_of(struct device_node *node,
-				     struct simple_card_data *priv,
-				     struct device *dev,
-				     int multi)
+				     struct simple_card_data *priv)
 {
-	struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link;
-	struct simple_dai_props *dai_props = priv->dai_props;
+	struct device *dev = simple_priv_to_dev(priv);
 	u32 val;
 	int ret;
 
-	/* parsing the card name from DT */
+	if (!node)
+		return -EINVAL;
+
+	/* Parse the card name from DT */
 	snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name");
 
-	/* off-codec widgets */
+	/* The off-codec widgets */
 	if (of_property_read_bool(node, "simple-audio-card,widgets")) {
 		ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card,
 					"simple-audio-card,widgets");
@@ -332,32 +414,45 @@
 	dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ?
 		priv->snd_card.name : "");
 
-	if (multi) {
+	/* Single/Muti DAI link(s) & New style of DT node */
+	if (of_get_child_by_name(node, "simple-audio-card,dai-link")) {
 		struct device_node *np = NULL;
-		int i;
-		for (i = 0; (np = of_get_next_child(node, np)); i++) {
+		int i = 0;
+
+		for_each_child_of_node(node, np) {
 			dev_dbg(dev, "\tlink %d:\n", i);
-			ret = simple_card_dai_link_of(np, dev, dai_link + i,
-						      dai_props + i, false);
+			ret = asoc_simple_card_dai_link_of(np, priv,
+							   i, false);
 			if (ret < 0) {
 				of_node_put(np);
 				return ret;
 			}
+			i++;
 		}
 	} else {
-		ret = simple_card_dai_link_of(node, dev, dai_link, dai_props,
-					      true);
+		/* For single DAI link & old style of DT node */
+		ret = asoc_simple_card_dai_link_of(node, priv, 0, true);
 		if (ret < 0)
 			return ret;
 	}
 
+	priv->gpio_hp_det = of_get_named_gpio(node,
+				"simple-audio-card,hp-det-gpio", 0);
+	if (priv->gpio_hp_det == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+
+	priv->gpio_mic_det = of_get_named_gpio(node,
+				"simple-audio-card,mic-det-gpio", 0);
+	if (priv->gpio_mic_det == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+
 	if (!priv->snd_card.name)
 		priv->snd_card.name = priv->snd_card.dai_link->name;
 
 	return 0;
 }
 
-/* update the reference count of the devices nodes at end of probe */
+/* Decrease the reference count of the device nodes */
 static int asoc_simple_card_unref(struct platform_device *pdev)
 {
 	struct snd_soc_card *card = platform_get_drvdata(pdev);
@@ -384,34 +479,32 @@
 	struct snd_soc_dai_link *dai_link;
 	struct device_node *np = pdev->dev.of_node;
 	struct device *dev = &pdev->dev;
-	int num_links, multi, ret;
+	int num_links, ret;
 
-	/* get the number of DAI links */
-	if (np && of_get_child_by_name(np, "simple-audio-card,dai-link")) {
+	/* Get the number of DAI links */
+	if (np && of_get_child_by_name(np, "simple-audio-card,dai-link"))
 		num_links = of_get_child_count(np);
-		multi = 1;
-	} else {
+	else
 		num_links = 1;
-		multi = 0;
-	}
 
-	/* allocate the private data and the DAI link array */
+	/* Allocate the private data and the DAI link array */
 	priv = devm_kzalloc(dev,
 			sizeof(*priv) + sizeof(*dai_link) * num_links,
 			GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
-	/*
-	 * init snd_soc_card
-	 */
+	/* Init snd_soc_card */
 	priv->snd_card.owner = THIS_MODULE;
 	priv->snd_card.dev = dev;
 	dai_link = priv->dai_link;
 	priv->snd_card.dai_link = dai_link;
 	priv->snd_card.num_links = num_links;
 
-	/* get room for the other properties */
+	priv->gpio_hp_det = -ENOENT;
+	priv->gpio_mic_det = -ENOENT;
+
+	/* Get room for the other properties */
 	priv->dai_props = devm_kzalloc(dev,
 			sizeof(*priv->dai_props) * num_links,
 			GFP_KERNEL);
@@ -420,25 +513,13 @@
 
 	if (np && of_device_is_available(np)) {
 
-		ret = asoc_simple_card_parse_of(np, priv, dev, multi);
+		ret = asoc_simple_card_parse_of(np, priv);
 		if (ret < 0) {
 			if (ret != -EPROBE_DEFER)
 				dev_err(dev, "parse error %d\n", ret);
 			goto err;
 		}
 
-		/*
-		 * soc_bind_dai_link() will check cpu name
-		 * after of_node matching if dai_link has cpu_dai_name.
-		 * but, it will never match if name was created by fmt_single_name()
-		 * remove cpu_dai_name to escape name matching.
-		 * see
-		 *	fmt_single_name()
-		 *	fmt_multiple_name()
-		 */
-		if (num_links == 1)
-			dai_link->cpu_dai_name = NULL;
-
 	} else {
 		struct asoc_simple_card_info *cinfo;
 
@@ -464,6 +545,7 @@
 		dai_link->codec_name	= cinfo->codec;
 		dai_link->cpu_dai_name	= cinfo->cpu_dai.name;
 		dai_link->codec_dai_name = cinfo->codec_dai.name;
+		dai_link->init		= asoc_simple_card_dai_init;
 		memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
 					sizeof(priv->dai_props->cpu_dai));
 		memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
@@ -473,11 +555,6 @@
 		priv->dai_props->codec_dai.fmt	|= cinfo->daifmt;
 	}
 
-	/*
-	 * init snd_soc_dai_link
-	 */
-	dai_link->init = asoc_simple_card_dai_init;
-
 	snd_soc_card_set_drvdata(&priv->snd_card, priv);
 
 	ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
@@ -491,6 +568,16 @@
 
 static int asoc_simple_card_remove(struct platform_device *pdev)
 {
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
+
+	if (gpio_is_valid(priv->gpio_hp_det))
+		snd_soc_jack_free_gpios(&simple_card_hp_jack, 1,
+					&simple_card_hp_jack_gpio);
+	if (gpio_is_valid(priv->gpio_mic_det))
+		snd_soc_jack_free_gpios(&simple_card_mic_jack, 1,
+					&simple_card_mic_jack_gpio);
+
 	return asoc_simple_card_unref(pdev);
 }
 
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile
index 7acbfc4..f841786 100644
--- a/sound/soc/intel/Makefile
+++ b/sound/soc/intel/Makefile
@@ -2,7 +2,8 @@
 snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o
 snd-soc-sst-acpi-objs := sst-acpi.o
 
-snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o sst-mfld-platform-compress.o
+snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o \
+	sst-mfld-platform-compress.o sst-atom-controls.o
 snd-soc-mfld-machine-objs := mfld_machine.o
 
 obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o
diff --git a/sound/soc/intel/byt-max98090.c b/sound/soc/intel/byt-max98090.c
index b8b8af5..d52681e 100644
--- a/sound/soc/intel/byt-max98090.c
+++ b/sound/soc/intel/byt-max98090.c
@@ -139,6 +139,7 @@
 	.num_dapm_routes = ARRAY_SIZE(byt_max98090_audio_map),
 	.controls = byt_max98090_controls,
 	.num_controls = ARRAY_SIZE(byt_max98090_controls),
+	.fully_routed = true,
 };
 
 static int byt_max98090_probe(struct platform_device *pdev)
diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c
index 234a58d..e03abdf 100644
--- a/sound/soc/intel/byt-rt5640.c
+++ b/sound/soc/intel/byt-rt5640.c
@@ -17,6 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/acpi.h>
 #include <linux/device.h>
+#include <linux/dmi.h>
 #include <linux/slab.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -36,8 +37,6 @@
 static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
 	{"Headset Mic", NULL, "MICBIAS1"},
 	{"IN2P", NULL, "Headset Mic"},
-	{"IN2N", NULL, "Headset Mic"},
-	{"DMIC1", NULL, "Internal Mic"},
 	{"Headphone", NULL, "HPOL"},
 	{"Headphone", NULL, "HPOR"},
 	{"Speaker", NULL, "SPOLP"},
@@ -46,6 +45,31 @@
 	{"Speaker", NULL, "SPORN"},
 };
 
+static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = {
+	{"DMIC1", NULL, "Internal Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic2_map[] = {
+	{"DMIC2", NULL, "Internal Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = {
+	{"Internal Mic", NULL, "MICBIAS1"},
+	{"IN1P", NULL, "Internal Mic"},
+};
+
+enum {
+	BYT_RT5640_DMIC1_MAP,
+	BYT_RT5640_DMIC2_MAP,
+	BYT_RT5640_IN1_MAP,
+};
+
+#define BYT_RT5640_MAP(quirk)	((quirk) & 0xff)
+#define BYT_RT5640_DMIC_EN	BIT(16)
+
+static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP |
+					BYT_RT5640_DMIC_EN;
+
 static const struct snd_kcontrol_new byt_rt5640_controls[] = {
 	SOC_DAPM_PIN_SWITCH("Headphone"),
 	SOC_DAPM_PIN_SWITCH("Headset Mic"),
@@ -77,12 +101,41 @@
 	return 0;
 }
 
+static int byt_rt5640_quirk_cb(const struct dmi_system_id *id)
+{
+	byt_rt5640_quirk = (unsigned long)id->driver_data;
+	return 1;
+}
+
+static const struct dmi_system_id byt_rt5640_quirk_table[] = {
+	{
+		.callback = byt_rt5640_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),
+		},
+		.driver_data = (unsigned long *)BYT_RT5640_IN1_MAP,
+	},
+	{
+		.callback = byt_rt5640_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "DellInc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"),
+		},
+		.driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP |
+						 BYT_RT5640_DMIC_EN),
+	},
+	{}
+};
+
 static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
 {
 	int ret;
 	struct snd_soc_codec *codec = runtime->codec;
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	struct snd_soc_card *card = runtime->card;
+	const struct snd_soc_dapm_route *custom_map;
+	int num_routes;
 
 	card->dapm.idle_bias_off = true;
 
@@ -93,6 +146,31 @@
 		return ret;
 	}
 
+	dmi_check_system(byt_rt5640_quirk_table);
+	switch (BYT_RT5640_MAP(byt_rt5640_quirk)) {
+	case BYT_RT5640_IN1_MAP:
+		custom_map = byt_rt5640_intmic_in1_map;
+		num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map);
+		break;
+	case BYT_RT5640_DMIC2_MAP:
+		custom_map = byt_rt5640_intmic_dmic2_map;
+		num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map);
+		break;
+	default:
+		custom_map = byt_rt5640_intmic_dmic1_map;
+		num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map);
+	}
+
+	ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes);
+	if (ret)
+		return ret;
+
+	if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) {
+		ret = rt5640_dmic_enable(codec, 0, 0);
+		if (ret)
+			return ret;
+	}
+
 	snd_soc_dapm_ignore_suspend(dapm, "HPOL");
 	snd_soc_dapm_ignore_suspend(dapm, "HPOR");
 
@@ -131,6 +209,7 @@
 	.num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets),
 	.dapm_routes = byt_rt5640_audio_map,
 	.num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
+	.fully_routed = true,
 };
 
 static int byt_rt5640_probe(struct platform_device *pdev)
diff --git a/sound/soc/intel/sst-atom-controls.c b/sound/soc/intel/sst-atom-controls.c
new file mode 100644
index 0000000..7104a34
--- /dev/null
+++ b/sound/soc/intel/sst-atom-controls.c
@@ -0,0 +1,218 @@
+/*
+ *  sst-atom-controls.c - Intel MID Platform driver DPCM ALSA controls for Mrfld
+ *
+ *  Copyright (C) 2013-14 Intel Corp
+ *  Author: Omair Mohammed Abdullah <omair.m.abdullah@intel.com>
+ *	Vinod Koul <vinod.koul@intel.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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "sst-mfld-platform.h"
+#include "sst-atom-controls.h"
+
+static int sst_fill_byte_control(struct sst_data *drv,
+					 u8 ipc_msg, u8 block,
+					 u8 task_id, u8 pipe_id,
+					 u16 len, void *cmd_data)
+{
+	struct snd_sst_bytes_v2 *byte_data = drv->byte_stream;
+
+	byte_data->type = SST_CMD_BYTES_SET;
+	byte_data->ipc_msg = ipc_msg;
+	byte_data->block = block;
+	byte_data->task_id = task_id;
+	byte_data->pipe_id = pipe_id;
+
+	if (len > SST_MAX_BIN_BYTES - sizeof(*byte_data)) {
+		dev_err(&drv->pdev->dev, "command length too big (%u)", len);
+		return -EINVAL;
+	}
+	byte_data->len = len;
+	memcpy(byte_data->bytes, cmd_data, len);
+	print_hex_dump_bytes("writing to lpe: ", DUMP_PREFIX_OFFSET,
+			     byte_data, len + sizeof(*byte_data));
+	return 0;
+}
+
+static int sst_fill_and_send_cmd_unlocked(struct sst_data *drv,
+				 u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id,
+				 void *cmd_data, u16 len)
+{
+	int ret = 0;
+
+	ret = sst_fill_byte_control(drv, ipc_msg,
+				block, task_id, pipe_id, len, cmd_data);
+	if (ret < 0)
+		return ret;
+	return sst->ops->send_byte_stream(sst->dev, drv->byte_stream);
+}
+
+/**
+ * sst_fill_and_send_cmd - generate the IPC message and send it to the FW
+ * @ipc_msg:	type of IPC (CMD, SET_PARAMS, GET_PARAMS)
+ * @cmd_data:	the IPC payload
+ */
+static int sst_fill_and_send_cmd(struct sst_data *drv,
+				 u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id,
+				 void *cmd_data, u16 len)
+{
+	int ret;
+
+	mutex_lock(&drv->lock);
+	ret = sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block,
+					task_id, pipe_id, cmd_data, len);
+	mutex_unlock(&drv->lock);
+
+	return ret;
+}
+
+static int sst_send_algo_cmd(struct sst_data *drv,
+			      struct sst_algo_control *bc)
+{
+	int len, ret = 0;
+	struct sst_cmd_set_params *cmd;
+
+	/*bc->max includes sizeof algos + length field*/
+	len = sizeof(cmd->dst) + sizeof(cmd->command_id) + bc->max;
+
+	cmd = kzalloc(len, GFP_KERNEL);
+	if (cmd == NULL)
+		return -ENOMEM;
+
+	SST_FILL_DESTINATION(2, cmd->dst, bc->pipe_id, bc->module_id);
+	cmd->command_id = bc->cmd_id;
+	memcpy(cmd->params, bc->params, bc->max);
+
+	ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS,
+				SST_FLAG_BLOCKED, bc->task_id, 0, cmd, len);
+	kfree(cmd);
+	return ret;
+}
+
+static int sst_algo_bytes_ctl_info(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_info *uinfo)
+{
+	struct sst_algo_control *bc = (void *)kcontrol->private_value;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = bc->max;
+
+	return 0;
+}
+
+static int sst_algo_control_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct sst_algo_control *bc = (void *)kcontrol->private_value;
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+
+	switch (bc->type) {
+	case SST_ALGO_PARAMS:
+		memcpy(ucontrol->value.bytes.data, bc->params, bc->max);
+		break;
+	default:
+		dev_err(component->dev, "Invalid Input- algo type:%d\n",
+				bc->type);
+		return -EINVAL;
+
+	}
+	return 0;
+}
+
+static int sst_algo_control_set(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int ret = 0;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt);
+	struct sst_algo_control *bc = (void *)kcontrol->private_value;
+
+	dev_dbg(cmpnt->dev, "control_name=%s\n", kcontrol->id.name);
+	mutex_lock(&drv->lock);
+	switch (bc->type) {
+	case SST_ALGO_PARAMS:
+		memcpy(bc->params, ucontrol->value.bytes.data, bc->max);
+		break;
+	default:
+		mutex_unlock(&drv->lock);
+		dev_err(cmpnt->dev, "Invalid Input- algo type:%d\n",
+				bc->type);
+		return -EINVAL;
+	}
+	/*if pipe is enabled, need to send the algo params from here*/
+	if (bc->w && bc->w->power)
+		ret = sst_send_algo_cmd(drv, bc);
+	mutex_unlock(&drv->lock);
+
+	return ret;
+}
+
+static const struct snd_kcontrol_new sst_algo_controls[] = {
+	SST_ALGO_KCONTROL_BYTES("media_loop1_out", "fir", 272, SST_MODULE_ID_FIR_24,
+		 SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR),
+	SST_ALGO_KCONTROL_BYTES("media_loop1_out", "iir", 300, SST_MODULE_ID_IIR_24,
+		SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
+	SST_ALGO_KCONTROL_BYTES("media_loop1_out", "mdrp", 286, SST_MODULE_ID_MDRP,
+		SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP),
+	SST_ALGO_KCONTROL_BYTES("media_loop2_out", "fir", 272, SST_MODULE_ID_FIR_24,
+		SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR),
+	SST_ALGO_KCONTROL_BYTES("media_loop2_out", "iir", 300, SST_MODULE_ID_IIR_24,
+		SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
+	SST_ALGO_KCONTROL_BYTES("media_loop2_out", "mdrp", 286, SST_MODULE_ID_MDRP,
+		SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP),
+	SST_ALGO_KCONTROL_BYTES("sprot_loop_out", "lpro", 192, SST_MODULE_ID_SPROT,
+		SST_PATH_INDEX_SPROT_LOOP_OUT, 0, SST_TASK_SBA, SBA_VB_LPRO),
+	SST_ALGO_KCONTROL_BYTES("codec_in0", "dcr", 52, SST_MODULE_ID_FILT_DCR,
+		SST_PATH_INDEX_CODEC_IN0, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
+	SST_ALGO_KCONTROL_BYTES("codec_in1", "dcr", 52, SST_MODULE_ID_FILT_DCR,
+		SST_PATH_INDEX_CODEC_IN1, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
+
+};
+
+static int sst_algo_control_init(struct device *dev)
+{
+	int i = 0;
+	struct sst_algo_control *bc;
+	/*allocate space to cache the algo parameters in the driver*/
+	for (i = 0; i < ARRAY_SIZE(sst_algo_controls); i++) {
+		bc = (struct sst_algo_control *)sst_algo_controls[i].private_value;
+		bc->params = devm_kzalloc(dev, bc->max, GFP_KERNEL);
+		if (bc->params == NULL)
+			return -ENOMEM;
+	}
+	return 0;
+}
+
+int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform)
+{
+	int ret = 0;
+	struct sst_data *drv = snd_soc_platform_get_drvdata(platform);
+
+	drv->byte_stream = devm_kzalloc(platform->dev,
+					SST_MAX_BIN_BYTES, GFP_KERNEL);
+	if (!drv->byte_stream)
+		return -ENOMEM;
+
+	/*Initialize algo control params*/
+	ret = sst_algo_control_init(platform->dev);
+	if (ret)
+		return ret;
+	ret = snd_soc_add_platform_controls(platform, sst_algo_controls,
+			ARRAY_SIZE(sst_algo_controls));
+	return ret;
+}
diff --git a/sound/soc/intel/sst-atom-controls.h b/sound/soc/intel/sst-atom-controls.h
index 14063ab..a73e894 100644
--- a/sound/soc/intel/sst-atom-controls.h
+++ b/sound/soc/intel/sst-atom-controls.h
@@ -1,4 +1,6 @@
 /*
+ *  sst-atom-controls.h - Intel MID Platform driver header file
+ *
  *  Copyright (C) 2013-14 Intel Corp
  *  Author: Ramesh Babu <ramesh.babu.koul@intel.com>
  *  	Omair M Abdullah <omair.m.abdullah@intel.com>
@@ -18,13 +20,423 @@
  *
  */
 
-#ifndef __SST_CONTROLS_V2_H__
-#define __SST_CONTROLS_V2_H__
+#ifndef __SST_ATOM_CONTROLS_H__
+#define __SST_ATOM_CONTROLS_H__
 
 enum {
 	MERR_DPCM_AUDIO = 0,
 	MERR_DPCM_COMPR,
 };
 
+/* define a bit for each mixer input */
+#define SST_MIX_IP(x)		(x)
+
+#define SST_IP_CODEC0		SST_MIX_IP(2)
+#define SST_IP_CODEC1		SST_MIX_IP(3)
+#define SST_IP_LOOP0		SST_MIX_IP(4)
+#define SST_IP_LOOP1		SST_MIX_IP(5)
+#define SST_IP_LOOP2		SST_MIX_IP(6)
+#define SST_IP_PROBE		SST_MIX_IP(7)
+#define SST_IP_VOIP		SST_MIX_IP(12)
+#define SST_IP_PCM0		SST_MIX_IP(13)
+#define SST_IP_PCM1		SST_MIX_IP(14)
+#define SST_IP_MEDIA0		SST_MIX_IP(17)
+#define SST_IP_MEDIA1		SST_MIX_IP(18)
+#define SST_IP_MEDIA2		SST_MIX_IP(19)
+#define SST_IP_MEDIA3		SST_MIX_IP(20)
+
+#define SST_IP_LAST		SST_IP_MEDIA3
+
+#define SST_SWM_INPUT_COUNT	(SST_IP_LAST + 1)
+#define SST_CMD_SWM_MAX_INPUTS	6
+
+#define SST_PATH_ID_SHIFT	8
+#define SST_DEFAULT_LOCATION_ID	0xFFFF
+#define SST_DEFAULT_CELL_NBR	0xFF
+#define SST_DEFAULT_MODULE_ID	0xFFFF
+
+/*
+ * Audio DSP Path Ids. Specified by the audio DSP FW
+ */
+enum sst_path_index {
+	SST_PATH_INDEX_CODEC_OUT0               = (0x02 << SST_PATH_ID_SHIFT),
+	SST_PATH_INDEX_CODEC_OUT1               = (0x03 << SST_PATH_ID_SHIFT),
+
+	SST_PATH_INDEX_SPROT_LOOP_OUT           = (0x04 << SST_PATH_ID_SHIFT),
+	SST_PATH_INDEX_MEDIA_LOOP1_OUT          = (0x05 << SST_PATH_ID_SHIFT),
+	SST_PATH_INDEX_MEDIA_LOOP2_OUT          = (0x06 << SST_PATH_ID_SHIFT),
+
+	SST_PATH_INDEX_VOIP_OUT                 = (0x0C << SST_PATH_ID_SHIFT),
+	SST_PATH_INDEX_PCM0_OUT                 = (0x0D << SST_PATH_ID_SHIFT),
+	SST_PATH_INDEX_PCM1_OUT                 = (0x0E << SST_PATH_ID_SHIFT),
+	SST_PATH_INDEX_PCM2_OUT                 = (0x0F << SST_PATH_ID_SHIFT),
+
+	SST_PATH_INDEX_MEDIA0_OUT               = (0x12 << SST_PATH_ID_SHIFT),
+	SST_PATH_INDEX_MEDIA1_OUT               = (0x13 << SST_PATH_ID_SHIFT),
+
+
+	/* Start of input paths */
+	SST_PATH_INDEX_CODEC_IN0                = (0x82 << SST_PATH_ID_SHIFT),
+	SST_PATH_INDEX_CODEC_IN1                = (0x83 << SST_PATH_ID_SHIFT),
+
+	SST_PATH_INDEX_SPROT_LOOP_IN            = (0x84 << SST_PATH_ID_SHIFT),
+	SST_PATH_INDEX_MEDIA_LOOP1_IN           = (0x85 << SST_PATH_ID_SHIFT),
+	SST_PATH_INDEX_MEDIA_LOOP2_IN           = (0x86 << SST_PATH_ID_SHIFT),
+
+	SST_PATH_INDEX_VOIP_IN                  = (0x8C << SST_PATH_ID_SHIFT),
+
+	SST_PATH_INDEX_PCM0_IN                  = (0x8D << SST_PATH_ID_SHIFT),
+	SST_PATH_INDEX_PCM1_IN                  = (0x8E << SST_PATH_ID_SHIFT),
+
+	SST_PATH_INDEX_MEDIA0_IN                = (0x8F << SST_PATH_ID_SHIFT),
+	SST_PATH_INDEX_MEDIA1_IN                = (0x90 << SST_PATH_ID_SHIFT),
+	SST_PATH_INDEX_MEDIA2_IN                = (0x91 << SST_PATH_ID_SHIFT),
+
+	SST_PATH_INDEX_MEDIA3_IN		= (0x9C << SST_PATH_ID_SHIFT),
+
+	SST_PATH_INDEX_RESERVED                 = (0xFF << SST_PATH_ID_SHIFT),
+};
+
+/*
+ * path IDs
+ */
+enum sst_swm_inputs {
+	SST_SWM_IN_CODEC0	= (SST_PATH_INDEX_CODEC_IN0	  | SST_DEFAULT_CELL_NBR),
+	SST_SWM_IN_CODEC1	= (SST_PATH_INDEX_CODEC_IN1	  | SST_DEFAULT_CELL_NBR),
+	SST_SWM_IN_SPROT_LOOP	= (SST_PATH_INDEX_SPROT_LOOP_IN	  | SST_DEFAULT_CELL_NBR),
+	SST_SWM_IN_MEDIA_LOOP1	= (SST_PATH_INDEX_MEDIA_LOOP1_IN  | SST_DEFAULT_CELL_NBR),
+	SST_SWM_IN_MEDIA_LOOP2	= (SST_PATH_INDEX_MEDIA_LOOP2_IN  | SST_DEFAULT_CELL_NBR),
+	SST_SWM_IN_VOIP		= (SST_PATH_INDEX_VOIP_IN	  | SST_DEFAULT_CELL_NBR),
+	SST_SWM_IN_PCM0		= (SST_PATH_INDEX_PCM0_IN	  | SST_DEFAULT_CELL_NBR),
+	SST_SWM_IN_PCM1		= (SST_PATH_INDEX_PCM1_IN	  | SST_DEFAULT_CELL_NBR),
+	SST_SWM_IN_MEDIA0	= (SST_PATH_INDEX_MEDIA0_IN	  | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+	SST_SWM_IN_MEDIA1	= (SST_PATH_INDEX_MEDIA1_IN	  | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+	SST_SWM_IN_MEDIA2	= (SST_PATH_INDEX_MEDIA2_IN	  | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+	SST_SWM_IN_MEDIA3	= (SST_PATH_INDEX_MEDIA3_IN	  | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+	SST_SWM_IN_END		= (SST_PATH_INDEX_RESERVED	  | SST_DEFAULT_CELL_NBR)
+};
+
+/*
+ * path IDs
+ */
+enum sst_swm_outputs {
+	SST_SWM_OUT_CODEC0	= (SST_PATH_INDEX_CODEC_OUT0	  | SST_DEFAULT_CELL_NBR),
+	SST_SWM_OUT_CODEC1	= (SST_PATH_INDEX_CODEC_OUT1	  | SST_DEFAULT_CELL_NBR),
+	SST_SWM_OUT_SPROT_LOOP	= (SST_PATH_INDEX_SPROT_LOOP_OUT  | SST_DEFAULT_CELL_NBR),
+	SST_SWM_OUT_MEDIA_LOOP1	= (SST_PATH_INDEX_MEDIA_LOOP1_OUT | SST_DEFAULT_CELL_NBR),
+	SST_SWM_OUT_MEDIA_LOOP2	= (SST_PATH_INDEX_MEDIA_LOOP2_OUT | SST_DEFAULT_CELL_NBR),
+	SST_SWM_OUT_VOIP	= (SST_PATH_INDEX_VOIP_OUT	  | SST_DEFAULT_CELL_NBR),
+	SST_SWM_OUT_PCM0	= (SST_PATH_INDEX_PCM0_OUT	  | SST_DEFAULT_CELL_NBR),
+	SST_SWM_OUT_PCM1	= (SST_PATH_INDEX_PCM1_OUT	  | SST_DEFAULT_CELL_NBR),
+	SST_SWM_OUT_PCM2	= (SST_PATH_INDEX_PCM2_OUT	  | SST_DEFAULT_CELL_NBR),
+	SST_SWM_OUT_MEDIA0	= (SST_PATH_INDEX_MEDIA0_OUT	  | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+	SST_SWM_OUT_MEDIA1	= (SST_PATH_INDEX_MEDIA1_OUT	  | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+	SST_SWM_OUT_END		= (SST_PATH_INDEX_RESERVED	  | SST_DEFAULT_CELL_NBR),
+};
+
+enum sst_ipc_msg {
+	SST_IPC_IA_CMD = 1,
+	SST_IPC_IA_SET_PARAMS,
+	SST_IPC_IA_GET_PARAMS,
+};
+
+enum sst_cmd_type {
+	SST_CMD_BYTES_SET = 1,
+	SST_CMD_BYTES_GET = 2,
+};
+
+enum sst_task {
+	SST_TASK_SBA = 1,
+	SST_TASK_MMX,
+};
+
+enum sst_type {
+	SST_TYPE_CMD = 1,
+	SST_TYPE_PARAMS,
+};
+
+enum sst_flag {
+	SST_FLAG_BLOCKED = 1,
+	SST_FLAG_NONBLOCK,
+};
+
+/*
+ * Enumeration for indexing the gain cells in VB_SET_GAIN DSP command
+ */
+enum sst_gain_index {
+	/* GAIN IDs for SB task start here */
+	SST_GAIN_INDEX_CODEC_OUT0,
+	SST_GAIN_INDEX_CODEC_OUT1,
+	SST_GAIN_INDEX_CODEC_IN0,
+	SST_GAIN_INDEX_CODEC_IN1,
+
+	SST_GAIN_INDEX_SPROT_LOOP_OUT,
+	SST_GAIN_INDEX_MEDIA_LOOP1_OUT,
+	SST_GAIN_INDEX_MEDIA_LOOP2_OUT,
+
+	SST_GAIN_INDEX_PCM0_IN_LEFT,
+	SST_GAIN_INDEX_PCM0_IN_RIGHT,
+
+	SST_GAIN_INDEX_PCM1_OUT_LEFT,
+	SST_GAIN_INDEX_PCM1_OUT_RIGHT,
+	SST_GAIN_INDEX_PCM1_IN_LEFT,
+	SST_GAIN_INDEX_PCM1_IN_RIGHT,
+	SST_GAIN_INDEX_PCM2_OUT_LEFT,
+
+	SST_GAIN_INDEX_PCM2_OUT_RIGHT,
+	SST_GAIN_INDEX_VOIP_OUT,
+	SST_GAIN_INDEX_VOIP_IN,
+
+	/* Gain IDs for MMX task start here */
+	SST_GAIN_INDEX_MEDIA0_IN_LEFT,
+	SST_GAIN_INDEX_MEDIA0_IN_RIGHT,
+	SST_GAIN_INDEX_MEDIA1_IN_LEFT,
+	SST_GAIN_INDEX_MEDIA1_IN_RIGHT,
+
+	SST_GAIN_INDEX_MEDIA2_IN_LEFT,
+	SST_GAIN_INDEX_MEDIA2_IN_RIGHT,
+
+	SST_GAIN_INDEX_GAIN_END
+};
+
+/*
+ * Audio DSP module IDs specified by FW spec
+ * TODO: Update with all modules
+ */
+enum sst_module_id {
+	SST_MODULE_ID_PCM		  = 0x0001,
+	SST_MODULE_ID_MP3		  = 0x0002,
+	SST_MODULE_ID_MP24		  = 0x0003,
+	SST_MODULE_ID_AAC		  = 0x0004,
+	SST_MODULE_ID_AACP		  = 0x0005,
+	SST_MODULE_ID_EAACP		  = 0x0006,
+	SST_MODULE_ID_WMA9		  = 0x0007,
+	SST_MODULE_ID_WMA10		  = 0x0008,
+	SST_MODULE_ID_WMA10P		  = 0x0009,
+	SST_MODULE_ID_RA		  = 0x000A,
+	SST_MODULE_ID_DDAC3		  = 0x000B,
+	SST_MODULE_ID_TRUE_HD		  = 0x000C,
+	SST_MODULE_ID_HD_PLUS		  = 0x000D,
+
+	SST_MODULE_ID_SRC		  = 0x0064,
+	SST_MODULE_ID_DOWNMIX		  = 0x0066,
+	SST_MODULE_ID_GAIN_CELL		  = 0x0067,
+	SST_MODULE_ID_SPROT		  = 0x006D,
+	SST_MODULE_ID_BASS_BOOST	  = 0x006E,
+	SST_MODULE_ID_STEREO_WDNG	  = 0x006F,
+	SST_MODULE_ID_AV_REMOVAL	  = 0x0070,
+	SST_MODULE_ID_MIC_EQ		  = 0x0071,
+	SST_MODULE_ID_SPL		  = 0x0072,
+	SST_MODULE_ID_ALGO_VTSV           = 0x0073,
+	SST_MODULE_ID_NR		  = 0x0076,
+	SST_MODULE_ID_BWX		  = 0x0077,
+	SST_MODULE_ID_DRP		  = 0x0078,
+	SST_MODULE_ID_MDRP		  = 0x0079,
+
+	SST_MODULE_ID_ANA		  = 0x007A,
+	SST_MODULE_ID_AEC		  = 0x007B,
+	SST_MODULE_ID_NR_SNS		  = 0x007C,
+	SST_MODULE_ID_SER		  = 0x007D,
+	SST_MODULE_ID_AGC		  = 0x007E,
+
+	SST_MODULE_ID_CNI		  = 0x007F,
+	SST_MODULE_ID_CONTEXT_ALGO_AWARE  = 0x0080,
+	SST_MODULE_ID_FIR_24		  = 0x0081,
+	SST_MODULE_ID_IIR_24		  = 0x0082,
+
+	SST_MODULE_ID_ASRC		  = 0x0083,
+	SST_MODULE_ID_TONE_GEN		  = 0x0084,
+	SST_MODULE_ID_BMF		  = 0x0086,
+	SST_MODULE_ID_EDL		  = 0x0087,
+	SST_MODULE_ID_GLC		  = 0x0088,
+
+	SST_MODULE_ID_FIR_16		  = 0x0089,
+	SST_MODULE_ID_IIR_16		  = 0x008A,
+	SST_MODULE_ID_DNR		  = 0x008B,
+
+	SST_MODULE_ID_VIRTUALIZER	  = 0x008C,
+	SST_MODULE_ID_VISUALIZATION	  = 0x008D,
+	SST_MODULE_ID_LOUDNESS_OPTIMIZER  = 0x008E,
+	SST_MODULE_ID_REVERBERATION	  = 0x008F,
+
+	SST_MODULE_ID_CNI_TX		  = 0x0090,
+	SST_MODULE_ID_REF_LINE		  = 0x0091,
+	SST_MODULE_ID_VOLUME		  = 0x0092,
+	SST_MODULE_ID_FILT_DCR		  = 0x0094,
+	SST_MODULE_ID_SLV		  = 0x009A,
+	SST_MODULE_ID_NLF		  = 0x009B,
+	SST_MODULE_ID_TNR		  = 0x009C,
+	SST_MODULE_ID_WNR		  = 0x009D,
+
+	SST_MODULE_ID_LOG		  = 0xFF00,
+
+	SST_MODULE_ID_TASK		  = 0xFFFF,
+};
+
+enum sst_cmd {
+	SBA_IDLE		= 14,
+	SBA_VB_SET_SPEECH_PATH	= 26,
+	MMX_SET_GAIN		= 33,
+	SBA_VB_SET_GAIN		= 33,
+	FBA_VB_RX_CNI		= 35,
+	MMX_SET_GAIN_TIMECONST	= 36,
+	SBA_VB_SET_TIMECONST	= 36,
+	SBA_VB_START		= 85,
+	SBA_SET_SWM		= 114,
+	SBA_SET_MDRP            = 116,
+	SBA_HW_SET_SSP		= 117,
+	SBA_SET_MEDIA_LOOP_MAP	= 118,
+	SBA_SET_MEDIA_PATH	= 119,
+	MMX_SET_MEDIA_PATH	= 119,
+	SBA_VB_LPRO             = 126,
+	SBA_VB_SET_FIR          = 128,
+	SBA_VB_SET_IIR          = 129,
+	SBA_SET_SSP_SLOT_MAP	= 130,
+};
+
+enum sst_dsp_switch {
+	SST_SWITCH_OFF = 0,
+	SST_SWITCH_ON = 3,
+};
+
+enum sst_path_switch {
+	SST_PATH_OFF = 0,
+	SST_PATH_ON = 1,
+};
+
+enum sst_swm_state {
+	SST_SWM_OFF = 0,
+	SST_SWM_ON = 3,
+};
+
+#define SST_FILL_LOCATION_IDS(dst, cell_idx, pipe_id)		do {	\
+		dst.location_id.p.cell_nbr_idx = (cell_idx);		\
+		dst.location_id.p.path_id = (pipe_id);			\
+	} while (0)
+#define SST_FILL_LOCATION_ID(dst, loc_id)				(\
+	dst.location_id.f = (loc_id))
+#define SST_FILL_MODULE_ID(dst, mod_id)					(\
+	dst.module_id = (mod_id))
+
+#define SST_FILL_DESTINATION1(dst, id)				do {	\
+		SST_FILL_LOCATION_ID(dst, (id) & 0xFFFF);		\
+		SST_FILL_MODULE_ID(dst, ((id) & 0xFFFF0000) >> 16);	\
+	} while (0)
+#define SST_FILL_DESTINATION2(dst, loc_id, mod_id)		do {	\
+		SST_FILL_LOCATION_ID(dst, loc_id);			\
+		SST_FILL_MODULE_ID(dst, mod_id);			\
+	} while (0)
+#define SST_FILL_DESTINATION3(dst, cell_idx, path_id, mod_id)	do {	\
+		SST_FILL_LOCATION_IDS(dst, cell_idx, path_id);		\
+		SST_FILL_MODULE_ID(dst, mod_id);			\
+	} while (0)
+
+#define SST_FILL_DESTINATION(level, dst, ...)				\
+	SST_FILL_DESTINATION##level(dst, __VA_ARGS__)
+#define SST_FILL_DEFAULT_DESTINATION(dst)				\
+	SST_FILL_DESTINATION(2, dst, SST_DEFAULT_LOCATION_ID, SST_DEFAULT_MODULE_ID)
+
+struct sst_destination_id {
+	union sst_location_id {
+		struct {
+			u8 cell_nbr_idx;	/* module index */
+			u8 path_id;		/* pipe_id */
+		} __packed	p;		/* part */
+		u16		f;		/* full */
+	} __packed location_id;
+	u16	   module_id;
+} __packed;
+struct sst_dsp_header {
+	struct sst_destination_id dst;
+	u16 command_id;
+	u16 length;
+} __packed;
+
+/*
+ *
+ * Common Commands
+ *
+ */
+struct sst_cmd_generic {
+	struct sst_dsp_header header;
+} __packed;
+struct sst_cmd_set_params {
+	struct sst_destination_id dst;
+	u16 command_id;
+	char params[0];
+} __packed;
+#define SST_CONTROL_NAME(xpname, xmname, xinstance, xtype) \
+	xpname " " xmname " " #xinstance " " xtype
+
+#define SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, xtype, xsubmodule) \
+	xpname " " xmname " " #xinstance " " xtype " " xsubmodule
+enum sst_algo_kcontrol_type {
+	SST_ALGO_PARAMS,
+	SST_ALGO_BYPASS,
+};
+
+struct sst_algo_control {
+	enum sst_algo_kcontrol_type type;
+	int max;
+	u16 module_id;
+	u16 pipe_id;
+	u16 task_id;
+	u16 cmd_id;
+	bool bypass;
+	unsigned char *params;
+	struct snd_soc_dapm_widget *w;
+};
+
+/* size of the control = size of params + size of length field */
+#define SST_ALGO_CTL_VALUE(xcount, xtype, xpipe, xmod, xtask, xcmd)			\
+	(struct sst_algo_control){							\
+		.max = xcount + sizeof(u16), .type = xtype, .module_id = xmod,			\
+		.pipe_id = xpipe, .task_id = xtask, .cmd_id = xcmd,			\
+	}
+
+#define SST_ALGO_KCONTROL(xname, xcount, xmod, xpipe,					\
+			  xtask, xcmd, xtype, xinfo, xget, xput)			\
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,						\
+	.name =  xname,									\
+	.info = xinfo, .get = xget, .put = xput,					\
+	.private_value = (unsigned long)&						\
+			SST_ALGO_CTL_VALUE(xcount, xtype, xpipe,			\
+					   xmod, xtask, xcmd),				\
+}
+
+#define SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod,				\
+				xpipe, xinstance, xtask, xcmd)				\
+	SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "params"),	\
+			  xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS,		\
+			  sst_algo_bytes_ctl_info,					\
+			  sst_algo_control_get, sst_algo_control_set)
+
+#define SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask)		\
+	SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "bypass"),	\
+			  0, xmod, xpipe, xtask, 0, SST_ALGO_BYPASS,			\
+			  snd_soc_info_bool_ext,					\
+			  sst_algo_control_get, sst_algo_control_set)
+
+#define SST_ALGO_BYPASS_PARAMS(xpname, xmname, xcount, xmod, xpipe,			\
+				xinstance, xtask, xcmd)					\
+	SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask),		\
+	SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod, xpipe, xinstance, xtask, xcmd)
+
+#define SST_COMBO_ALGO_KCONTROL_BYTES(xpname, xmname, xsubmod, xcount, xmod,		\
+				      xpipe, xinstance, xtask, xcmd)			\
+	SST_ALGO_KCONTROL(SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, "params",	\
+						 xsubmod),				\
+			  xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS,		\
+			  sst_algo_bytes_ctl_info,					\
+			  sst_algo_control_get, sst_algo_control_set)
+
+
+struct sst_enum {
+	bool tx;
+	unsigned short reg;
+	unsigned int max;
+	const char * const *texts;
+	struct snd_soc_dapm_widget *w;
+};
 
 #endif
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c
index 61bf6da..33fc5c3 100644
--- a/sound/soc/intel/sst-haswell-pcm.c
+++ b/sound/soc/intel/sst-haswell-pcm.c
@@ -138,11 +138,10 @@
 static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt);
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
-	struct hsw_priv_data *pdata =
-		snd_soc_platform_get_drvdata(platform);
 	struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
 	struct sst_hsw *hsw = pdata->hsw;
 	u32 volume;
@@ -176,11 +175,10 @@
 static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt);
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
-	struct hsw_priv_data *pdata =
-		snd_soc_platform_get_drvdata(platform);
 	struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
 	struct sst_hsw *hsw = pdata->hsw;
 	u32 volume;
@@ -208,8 +206,8 @@
 static int hsw_volume_put(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
-	struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt);
 	struct sst_hsw *hsw = pdata->hsw;
 	u32 volume;
 
@@ -233,8 +231,8 @@
 static int hsw_volume_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
-	struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt);
 	struct sst_hsw *hsw = pdata->hsw;
 	unsigned int volume = 0;
 
@@ -778,20 +776,11 @@
 
 static int hsw_pcm_probe(struct snd_soc_platform *platform)
 {
+	struct hsw_priv_data *priv_data = snd_soc_platform_get_drvdata(platform);
 	struct sst_pdata *pdata = dev_get_platdata(platform->dev);
-	struct hsw_priv_data *priv_data;
-	struct device *dma_dev;
+	struct device *dma_dev = pdata->dma_dev;
 	int i, ret = 0;
 
-	if (!pdata)
-		return -ENODEV;
-
-	dma_dev = pdata->dma_dev;
-
-	priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL);
-	priv_data->hsw = pdata->dsp;
-	snd_soc_platform_set_drvdata(platform, priv_data);
-
 	/* allocate DSP buffer page tables */
 	for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
 
@@ -848,27 +837,38 @@
 	.ops		= &hsw_pcm_ops,
 	.pcm_new	= hsw_pcm_new,
 	.pcm_free	= hsw_pcm_free,
-	.controls	= hsw_volume_controls,
-	.num_controls	= ARRAY_SIZE(hsw_volume_controls),
-	.dapm_widgets	= widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(widgets),
-	.dapm_routes	= graph,
-	.num_dapm_routes	= ARRAY_SIZE(graph),
 };
 
 static const struct snd_soc_component_driver hsw_dai_component = {
-	.name		= "haswell-dai",
+	.name = "haswell-dai",
+	.controls = hsw_volume_controls,
+	.num_controls = ARRAY_SIZE(hsw_volume_controls),
+	.dapm_widgets = widgets,
+	.num_dapm_widgets = ARRAY_SIZE(widgets),
+	.dapm_routes = graph,
+	.num_dapm_routes = ARRAY_SIZE(graph),
 };
 
 static int hsw_pcm_dev_probe(struct platform_device *pdev)
 {
 	struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
+	struct hsw_priv_data *priv_data;
 	int ret;
 
+	if (!sst_pdata)
+		return -EINVAL;
+
+	priv_data = devm_kzalloc(&pdev->dev, sizeof(*priv_data), GFP_KERNEL);
+	if (!priv_data)
+		return -ENOMEM;
+
 	ret = sst_hsw_dsp_init(&pdev->dev, sst_pdata);
 	if (ret < 0)
 		return -ENODEV;
 
+	priv_data->hsw = sst_pdata->dsp;
+	platform_set_drvdata(pdev, priv_data);
+
 	ret = snd_soc_register_platform(&pdev->dev, &hsw_soc_platform);
 	if (ret < 0)
 		goto err_plat;
diff --git a/sound/soc/intel/sst-mfld-platform-compress.c b/sound/soc/intel/sst-mfld-platform-compress.c
index 29c059ca..59467775 100644
--- a/sound/soc/intel/sst-mfld-platform-compress.c
+++ b/sound/soc/intel/sst-mfld-platform-compress.c
@@ -86,7 +86,7 @@
 	/*need to check*/
 	str_id = stream->id;
 	if (str_id)
-		ret_val = stream->compr_ops->close(str_id);
+		ret_val = stream->compr_ops->close(sst->dev, str_id);
 	module_put(sst->dev->driver->owner);
 	kfree(stream);
 	pr_debug("%s: %d\n", __func__, ret_val);
@@ -158,7 +158,7 @@
 	cb.drain_cb_param = cstream;
 	cb.drain_notify = sst_drain_notify;
 
-	retval = stream->compr_ops->open(&str_params, &cb);
+	retval = stream->compr_ops->open(sst->dev, &str_params, &cb);
 	if (retval < 0) {
 		pr_err("stream allocation failed %d\n", retval);
 		return retval;
@@ -170,10 +170,30 @@
 
 static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd)
 {
-	struct sst_runtime_stream *stream =
-		cstream->runtime->private_data;
+	struct sst_runtime_stream *stream = cstream->runtime->private_data;
 
-	return stream->compr_ops->control(cmd, stream->id);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		if (stream->compr_ops->stream_start)
+			return stream->compr_ops->stream_start(sst->dev, stream->id);
+	case SNDRV_PCM_TRIGGER_STOP:
+		if (stream->compr_ops->stream_drop)
+			return stream->compr_ops->stream_drop(sst->dev, stream->id);
+	case SND_COMPR_TRIGGER_DRAIN:
+		if (stream->compr_ops->stream_drain)
+			return stream->compr_ops->stream_drain(sst->dev, stream->id);
+	case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
+		if (stream->compr_ops->stream_partial_drain)
+			return stream->compr_ops->stream_partial_drain(sst->dev, stream->id);
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if (stream->compr_ops->stream_pause)
+			return stream->compr_ops->stream_pause(sst->dev, stream->id);
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if (stream->compr_ops->stream_pause_release)
+			return stream->compr_ops->stream_pause_release(sst->dev, stream->id);
+	default:
+		return -EINVAL;
+	}
 }
 
 static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
@@ -182,7 +202,7 @@
 	struct sst_runtime_stream *stream;
 
 	stream  = cstream->runtime->private_data;
-	stream->compr_ops->tstamp(stream->id, tstamp);
+	stream->compr_ops->tstamp(sst->dev, stream->id, tstamp);
 	tstamp->byte_offset = tstamp->copied_total %
 				 (u32)cstream->runtime->buffer_size;
 	pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset);
@@ -195,7 +215,7 @@
 	struct sst_runtime_stream *stream;
 
 	stream  = cstream->runtime->private_data;
-	stream->compr_ops->ack(stream->id, (unsigned long)bytes);
+	stream->compr_ops->ack(sst->dev, stream->id, (unsigned long)bytes);
 	stream->bytes_written += bytes;
 
 	return 0;
@@ -225,7 +245,7 @@
 	struct sst_runtime_stream *stream  =
 		 cstream->runtime->private_data;
 
-	return stream->compr_ops->set_metadata(stream->id, metadata);
+	return stream->compr_ops->set_metadata(sst->dev, stream->id, metadata);
 }
 
 struct snd_compr_ops sst_platform_compr_ops = {
diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c
index 706212a..aa9b600 100644
--- a/sound/soc/intel/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/sst-mfld-platform-pcm.c
@@ -43,12 +43,12 @@
 		return -ENODEV;
 	mutex_lock(&sst_lock);
 	if (sst) {
-		pr_err("we already have a device %s\n", sst->name);
+		dev_err(dev->dev, "we already have a device %s\n", sst->name);
 		module_put(dev->dev->driver->owner);
 		mutex_unlock(&sst_lock);
 		return -EEXIST;
 	}
-	pr_debug("registering device %s\n", dev->name);
+	dev_dbg(dev->dev, "registering device %s\n", dev->name);
 	sst = dev;
 	mutex_unlock(&sst_lock);
 	return 0;
@@ -70,7 +70,7 @@
 	}
 
 	module_put(sst->dev->driver->owner);
-	pr_debug("unreg %s\n", sst->name);
+	dev_dbg(dev->dev, "unreg %s\n", sst->name);
 	sst = NULL;
 	mutex_unlock(&sst_lock);
 	return 0;
@@ -252,7 +252,7 @@
 }
 
 static int sst_platform_alloc_stream(struct snd_pcm_substream *substream,
-		struct snd_soc_platform *platform)
+		struct snd_soc_dai *dai)
 {
 	struct sst_runtime_stream *stream =
 			substream->runtime->private_data;
@@ -260,7 +260,7 @@
 	struct snd_sst_params str_params = {0};
 	struct snd_sst_alloc_params_ext alloc_params = {0};
 	int ret_val = 0;
-	struct sst_data *ctx = snd_soc_platform_get_drvdata(platform);
+	struct sst_data *ctx = snd_soc_dai_get_drvdata(dai);
 
 	/* set codec params and inform SST driver the same */
 	sst_fill_pcm_params(substream, &param);
@@ -277,7 +277,7 @@
 
 	stream->stream_info.str_id = str_params.stream_id;
 
-	ret_val = stream->ops->open(&str_params);
+	ret_val = stream->ops->open(sst->dev, &str_params);
 	if (ret_val <= 0)
 		return ret_val;
 
@@ -306,22 +306,31 @@
 {
 	struct sst_runtime_stream *stream =
 			substream->runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	int ret_val;
 
-	pr_debug("setting buffer ptr param\n");
+	dev_dbg(rtd->dev, "setting buffer ptr param\n");
 	sst_set_stream_status(stream, SST_PLATFORM_INIT);
 	stream->stream_info.period_elapsed = sst_period_elapsed;
 	stream->stream_info.arg = substream;
 	stream->stream_info.buffer_ptr = 0;
 	stream->stream_info.sfreq = substream->runtime->rate;
-	ret_val = stream->ops->device_control(
-			SST_SND_STREAM_INIT, &stream->stream_info);
+	ret_val = stream->ops->stream_init(sst->dev, &stream->stream_info);
 	if (ret_val)
-		pr_err("control_set ret error %d\n", ret_val);
+		dev_err(rtd->dev, "control_set ret error %d\n", ret_val);
 	return ret_val;
 
 }
-/* end -- helper functions */
+
+static int power_up_sst(struct sst_runtime_stream *stream)
+{
+	return stream->ops->power(sst->dev, true);
+}
+
+static void power_down_sst(struct sst_runtime_stream *stream)
+{
+	stream->ops->power(sst->dev, false);
+}
 
 static int sst_media_open(struct snd_pcm_substream *substream,
 		struct snd_soc_dai *dai)
@@ -339,7 +348,7 @@
 	mutex_lock(&sst_lock);
 	if (!sst ||
 	    !try_module_get(sst->dev->driver->owner)) {
-		pr_err("no device available to run\n");
+		dev_err(dai->dev, "no device available to run\n");
 		ret_val = -ENODEV;
 		goto out_ops;
 	}
@@ -352,6 +361,10 @@
 	/* allocate memory for SST API set */
 	runtime->private_data = stream;
 
+	ret_val = power_up_sst(stream);
+	if (ret_val < 0)
+		return ret_val;
+
 	/* Make sure, that the period size is always even */
 	snd_pcm_hw_constraint_step(substream->runtime, 0,
 			   SNDRV_PCM_HW_PARAM_PERIODS, 2);
@@ -371,26 +384,29 @@
 	int ret_val = 0, str_id;
 
 	stream = substream->runtime->private_data;
+	power_down_sst(stream);
+
 	str_id = stream->stream_info.str_id;
 	if (str_id)
-		ret_val = stream->ops->close(str_id);
+		ret_val = stream->ops->close(sst->dev, str_id);
 	module_put(sst->dev->driver->owner);
 	kfree(stream);
 }
 
-static inline unsigned int get_current_pipe_id(struct snd_soc_platform *platform,
+static inline unsigned int get_current_pipe_id(struct snd_soc_dai *dai,
 					       struct snd_pcm_substream *substream)
 {
-	struct sst_data *sst = snd_soc_platform_get_drvdata(platform);
+	struct sst_data *sst = snd_soc_dai_get_drvdata(dai);
 	struct sst_dev_stream_map *map = sst->pdata->pdev_strm_map;
 	struct sst_runtime_stream *stream =
 			substream->runtime->private_data;
 	u32 str_id = stream->stream_info.str_id;
 	unsigned int pipe_id;
+
 	pipe_id = map[str_id].device_id;
 
-	pr_debug("%s: got pipe_id = %#x for str_id = %d\n",
-		 __func__, pipe_id, str_id);
+	dev_dbg(dai->dev, "got pipe_id = %#x for str_id = %d\n",
+			pipe_id, str_id);
 	return pipe_id;
 }
 
@@ -403,12 +419,11 @@
 	stream = substream->runtime->private_data;
 	str_id = stream->stream_info.str_id;
 	if (stream->stream_info.str_id) {
-		ret_val = stream->ops->device_control(
-				SST_SND_DROP, &str_id);
+		ret_val = stream->ops->stream_drop(sst->dev, str_id);
 		return ret_val;
 	}
 
-	ret_val = sst_platform_alloc_stream(substream, dai->platform);
+	ret_val = sst_platform_alloc_stream(substream, dai);
 	if (ret_val <= 0)
 		return ret_val;
 	snprintf(substream->pcm->id, sizeof(substream->pcm->id),
@@ -461,37 +476,40 @@
 {
 	int ret_val = 0, str_id;
 	struct sst_runtime_stream *stream;
-	int str_cmd, status;
+	int status;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
-	pr_debug("sst_platform_pcm_trigger called\n");
+	dev_dbg(rtd->dev, "sst_platform_pcm_trigger called\n");
+	if (substream->pcm->internal)
+		return 0;
 	stream = substream->runtime->private_data;
 	str_id = stream->stream_info.str_id;
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
-		pr_debug("sst: Trigger Start\n");
-		str_cmd = SST_SND_START;
+		dev_dbg(rtd->dev, "sst: Trigger Start\n");
 		status = SST_PLATFORM_RUNNING;
 		stream->stream_info.arg = substream;
+		ret_val = stream->ops->stream_start(sst->dev, str_id);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
-		pr_debug("sst: in stop\n");
-		str_cmd = SST_SND_DROP;
+		dev_dbg(rtd->dev, "sst: in stop\n");
 		status = SST_PLATFORM_DROPPED;
+		ret_val = stream->ops->stream_drop(sst->dev, str_id);
 		break;
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		pr_debug("sst: in pause\n");
-		str_cmd = SST_SND_PAUSE;
+		dev_dbg(rtd->dev, "sst: in pause\n");
 		status = SST_PLATFORM_PAUSED;
+		ret_val = stream->ops->stream_pause(sst->dev, str_id);
 		break;
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		pr_debug("sst: in pause release\n");
-		str_cmd = SST_SND_RESUME;
+		dev_dbg(rtd->dev, "sst: in pause release\n");
 		status = SST_PLATFORM_RUNNING;
+		ret_val = stream->ops->stream_pause_release(sst->dev, str_id);
 		break;
 	default:
 		return -EINVAL;
 	}
-	ret_val = stream->ops->device_control(str_cmd, &str_id);
+
 	if (!ret_val)
 		sst_set_stream_status(stream, status);
 
@@ -505,16 +523,16 @@
 	struct sst_runtime_stream *stream;
 	int ret_val, status;
 	struct pcm_stream_info *str_info;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
 	stream = substream->runtime->private_data;
 	status = sst_get_stream_status(stream);
 	if (status == SST_PLATFORM_INIT)
 		return 0;
 	str_info = &stream->stream_info;
-	ret_val = stream->ops->device_control(
-				SST_SND_BUFFER_POINTER, str_info);
+	ret_val = stream->ops->stream_read_tstamp(sst->dev, str_info);
 	if (ret_val) {
-		pr_err("sst: error code = %d\n", ret_val);
+		dev_err(rtd->dev, "sst: error code = %d\n", ret_val);
 		return ret_val;
 	}
 	substream->runtime->delay = str_info->pcm_delay;
@@ -530,7 +548,7 @@
 
 static void sst_pcm_free(struct snd_pcm *pcm)
 {
-	pr_debug("sst_pcm_free called\n");
+	dev_dbg(pcm->dev, "sst_pcm_free called\n");
 	snd_pcm_lib_preallocate_free_for_all(pcm);
 }
 
@@ -547,14 +565,20 @@
 			snd_dma_continuous_data(GFP_DMA),
 			SST_MIN_BUFFER, SST_MAX_BUFFER);
 		if (retval) {
-			pr_err("dma buffer allocationf fail\n");
+			dev_err(rtd->dev, "dma buffer allocationf fail\n");
 			return retval;
 		}
 	}
 	return retval;
 }
 
-static struct snd_soc_platform_driver sst_soc_platform_drv = {
+static int sst_soc_probe(struct snd_soc_platform *platform)
+{
+	return sst_dsp_init_v2_dpcm(platform);
+}
+
+static struct snd_soc_platform_driver sst_soc_platform_drv  = {
+	.probe		= sst_soc_probe,
 	.ops		= &sst_platform_ops,
 	.compr_ops	= &sst_platform_compr_ops,
 	.pcm_new	= sst_pcm_new,
@@ -574,13 +598,11 @@
 
 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 	if (drv == NULL) {
-		pr_err("kzalloc failed\n");
 		return -ENOMEM;
 	}
 
 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 	if (pdata == NULL) {
-		pr_err("kzalloc failed for pdata\n");
 		return -ENOMEM;
 	}
 
@@ -592,14 +614,14 @@
 
 	ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv);
 	if (ret) {
-		pr_err("registering soc platform failed\n");
+		dev_err(&pdev->dev, "registering soc platform failed\n");
 		return ret;
 	}
 
 	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");
+		dev_err(&pdev->dev, "registering cpu dais failed\n");
 		snd_soc_unregister_platform(&pdev->dev);
 	}
 	return ret;
@@ -610,7 +632,7 @@
 
 	snd_soc_unregister_component(&pdev->dev);
 	snd_soc_unregister_platform(&pdev->dev);
-	pr_debug("sst_platform_remove success\n");
+	dev_dbg(&pdev->dev, "sst_platform_remove success\n");
 	return 0;
 }
 
diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h
index 6c6a42c..19f83ec 100644
--- a/sound/soc/intel/sst-mfld-platform.h
+++ b/sound/soc/intel/sst-mfld-platform.h
@@ -54,20 +54,6 @@
 	SST_PLATFORM_DROPPED,
 };
 
-enum sst_controls {
-	SST_SND_ALLOC =			0x00,
-	SST_SND_PAUSE =			0x01,
-	SST_SND_RESUME =		0x02,
-	SST_SND_DROP =			0x03,
-	SST_SND_FREE =			0x04,
-	SST_SND_BUFFER_POINTER =	0x05,
-	SST_SND_STREAM_INIT =		0x06,
-	SST_SND_START	 =		0x07,
-	SST_SET_BYTE_STREAM =           0x100A,
-	SST_GET_BYTE_STREAM =           0x100B,
-	SST_MAX_CONTROLS = SST_GET_BYTE_STREAM,
-};
-
 enum sst_stream_ops {
 	STREAM_OPS_PLAYBACK = 0,
 	STREAM_OPS_CAPTURE,
@@ -113,24 +99,37 @@
 
 struct compress_sst_ops {
 	const char *name;
-	int (*open) (struct snd_sst_params *str_params,
-			struct sst_compress_cb *cb);
-	int (*control) (unsigned int cmd, unsigned int str_id);
-	int (*tstamp) (unsigned int str_id, struct snd_compr_tstamp *tstamp);
-	int (*ack) (unsigned int str_id, unsigned long bytes);
-	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);
+	int (*open)(struct device *dev,
+		struct snd_sst_params *str_params, struct sst_compress_cb *cb);
+	int (*stream_start)(struct device *dev, unsigned int str_id);
+	int (*stream_drop)(struct device *dev, unsigned int str_id);
+	int (*stream_drain)(struct device *dev, unsigned int str_id);
+	int (*stream_partial_drain)(struct device *dev,	unsigned int str_id);
+	int (*stream_pause)(struct device *dev, unsigned int str_id);
+	int (*stream_pause_release)(struct device *dev,	unsigned int str_id);
 
+	int (*tstamp)(struct device *dev, unsigned int str_id,
+			struct snd_compr_tstamp *tstamp);
+	int (*ack)(struct device *dev, unsigned int str_id,
+			unsigned long bytes);
+	int (*close)(struct device *dev, 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)(struct device *dev,	unsigned int str_id,
+			struct snd_compr_metadata *mdata);
 };
 
 struct sst_ops {
-	int (*open) (struct snd_sst_params *str_param);
-	int (*device_control) (int cmd, void *arg);
-	int (*set_generic_params)(enum sst_controls cmd, void *arg);
-	int (*close) (unsigned int str_id);
+	int (*open)(struct device *dev, struct snd_sst_params *str_param);
+	int (*stream_init)(struct device *dev, struct pcm_stream_info *str_info);
+	int (*stream_start)(struct device *dev, int str_id);
+	int (*stream_drop)(struct device *dev, int str_id);
+	int (*stream_pause)(struct device *dev, int str_id);
+	int (*stream_pause_release)(struct device *dev, int str_id);
+	int (*stream_read_tstamp)(struct device *dev, struct pcm_stream_info *str_info);
+	int (*send_byte_stream)(struct device *dev, struct snd_sst_bytes_v2 *bytes);
+	int (*close)(struct device *dev, unsigned int str_id);
+	int (*power)(struct device *dev, bool state);
 };
 
 struct sst_runtime_stream {
@@ -152,6 +151,8 @@
 };
 
 struct sst_data;
+
+int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform);
 void sst_set_stream_status(struct sst_runtime_stream *stream, int state);
 int sst_fill_stream_params(void *substream, const struct sst_data *ctx,
 			   struct snd_sst_params *str_params, bool is_compress);
@@ -166,6 +167,7 @@
 struct sst_data {
 	struct platform_device *pdev;
 	struct sst_platform_data *pdata;
+	struct snd_sst_bytes_v2 *byte_stream;
 	struct mutex lock;
 };
 int sst_register_dsp(struct sst_device *sst);
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 943922c..b10ae80 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -168,7 +168,7 @@
 static int rx51_hp_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *k, int event)
 {
-	struct snd_soc_codec *codec = w->dapm->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	if (SND_SOC_DAPM_EVENT_ON(event))
 		tpa6130a2_stereo_enable(codec, 1);
diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig
index c196a46..78fc159 100644
--- a/sound/soc/rockchip/Kconfig
+++ b/sound/soc/rockchip/Kconfig
@@ -2,11 +2,10 @@
 	tristate "ASoC support for Rockchip"
 	depends on COMPILE_TEST || ARCH_ROCKCHIP
 	select SND_SOC_GENERIC_DMAENGINE_PCM
-	select SND_ROCKCHIP_I2S
 	help
 	  Say Y or M if you want to add support for codecs attached to
 	  the Rockchip SoCs' Audio interfaces. You will also need to
 	  select the audio interfaces to support below.
 
-config SND_ROCKCHIP_I2S
+config SND_SOC_ROCKCHIP_I2S
 	tristate
diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile
index 1006418..b921909 100644
--- a/sound/soc/rockchip/Makefile
+++ b/sound/soc/rockchip/Makefile
@@ -1,4 +1,4 @@
 # ROCKCHIP Platform Support
 snd-soc-i2s-objs := rockchip_i2s.o
 
-obj-$(CONFIG_SND_ROCKCHIP_I2S) += snd-soc-i2s.o
+obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-i2s.o
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index fb9e05c..f373e37 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -108,8 +108,10 @@
 			while (val) {
 				regmap_read(i2s->regmap, I2S_CLR, &val);
 				retry--;
-				if (!retry)
+				if (!retry) {
 					dev_warn(i2s->dev, "fail to clear\n");
+					break;
+				}
 			}
 		}
 	}
@@ -244,16 +246,6 @@
 	regmap_update_bits(i2s->regmap, I2S_TXCR, I2S_TXCR_VDW_MASK, val);
 	regmap_update_bits(i2s->regmap, I2S_RXCR, I2S_RXCR_VDW_MASK, val);
 
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		dai->playback_dma_data = &i2s->playback_dma_data;
-		regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK,
-				   I2S_DMACR_TDL(1) | I2S_DMACR_TDE_ENABLE);
-	} else {
-		dai->capture_dma_data = &i2s->capture_dma_data;
-		regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK,
-				   I2S_DMACR_RDL(1) | I2S_DMACR_RDE_ENABLE);
-	}
-
 	return 0;
 }
 
@@ -301,6 +293,16 @@
 	return ret;
 }
 
+static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+	struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
+
+	dai->capture_dma_data = &i2s->capture_dma_data;
+	dai->playback_dma_data = &i2s->playback_dma_data;
+
+	return 0;
+}
+
 static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
 	.hw_params = rockchip_i2s_hw_params,
 	.set_sysclk = rockchip_i2s_set_sysclk,
@@ -309,7 +311,9 @@
 };
 
 static struct snd_soc_dai_driver rockchip_i2s_dai = {
+	.probe = rockchip_i2s_dai_probe,
 	.playback = {
+		.stream_name = "Playback",
 		.channels_min = 2,
 		.channels_max = 8,
 		.rates = SNDRV_PCM_RATE_8000_192000,
@@ -319,6 +323,7 @@
 			    SNDRV_PCM_FMTBIT_S24_LE),
 	},
 	.capture = {
+		.stream_name = "Capture",
 		.channels_min = 2,
 		.channels_max = 2,
 		.rates = SNDRV_PCM_RATE_8000_192000,
@@ -420,6 +425,11 @@
 		dev_err(&pdev->dev, "Can't retrieve i2s bus clock\n");
 		return PTR_ERR(i2s->hclk);
 	}
+	ret = clk_prepare_enable(i2s->hclk);
+	if (ret) {
+		dev_err(i2s->dev, "hclock enable failed %d\n", ret);
+		return ret;
+	}
 
 	i2s->mclk = devm_clk_get(&pdev->dev, "i2s_clk");
 	if (IS_ERR(i2s->mclk)) {
diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c
index db6cefa..0e8dd98 100644
--- a/sound/soc/samsung/idma.c
+++ b/sound/soc/samsung/idma.c
@@ -351,7 +351,7 @@
 	if (!buf->area)
 		return;
 
-	iounmap(buf->area);
+	iounmap((void __iomem *)buf->area);
 
 	buf->area = NULL;
 	buf->addr = 0;
@@ -369,7 +369,7 @@
 	buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS;
 	buf->addr = idma.lp_tx_addr;
 	buf->bytes = idma_hardware.buffer_bytes_max;
-	buf->area = (unsigned char *)ioremap(buf->addr, buf->bytes);
+	buf->area = (unsigned char * __force)ioremap(buf->addr, buf->bytes);
 
 	return 0;
 }
diff --git a/sound/soc/samsung/odroidx2_max98090.c b/sound/soc/samsung/odroidx2_max98090.c
index 278edf9..3c8f604 100644
--- a/sound/soc/samsung/odroidx2_max98090.c
+++ b/sound/soc/samsung/odroidx2_max98090.c
@@ -66,12 +66,12 @@
 	.late_probe		= odroidx2_late_probe,
 };
 
-struct odroidx2_drv_data odroidx2_drvdata = {
+static const struct odroidx2_drv_data odroidx2_drvdata = {
 	.dapm_widgets		= odroidx2_dapm_widgets,
 	.num_dapm_widgets	= ARRAY_SIZE(odroidx2_dapm_widgets),
 };
 
-struct odroidx2_drv_data odroidu3_drvdata = {
+static const struct odroidx2_drv_data odroidu3_drvdata = {
 	.dapm_widgets		= odroidu3_dapm_widgets,
 	.num_dapm_widgets	= ARRAY_SIZE(odroidu3_dapm_widgets),
 };
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c
index 9902efc..a054826 100644
--- a/sound/soc/samsung/speyside.c
+++ b/sound/soc/samsung/speyside.c
@@ -228,10 +228,12 @@
 	},
 };
 
-static int speyside_wm9081_init(struct snd_soc_dapm_context *dapm)
+static int speyside_wm9081_init(struct snd_soc_component *component)
 {
+	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+
 	/* At any time the WM9081 is active it will have this clock */
-	return snd_soc_codec_set_sysclk(dapm->codec, WM9081_SYSCLK_MCLK, 0,
+	return snd_soc_codec_set_sysclk(codec, WM9081_SYSCLK_MCLK, 0,
 					MCLK_AUDIO_RATE, 0);
 }
 
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index c763443..66fddec 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -1297,9 +1297,14 @@
 	struct snd_pcm_substream *substream = io->substream;
 	struct dma_async_tx_descriptor *desc;
 	int is_play = fsi_stream_is_play(fsi, io);
-	enum dma_data_direction dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+	enum dma_transfer_direction dir;
 	int ret = -EIO;
 
+	if (is_play)
+		dir = DMA_MEM_TO_DEV;
+	else
+		dir = DMA_DEV_TO_MEM;
+
 	desc = dmaengine_prep_dma_cyclic(io->chan,
 					 substream->runtime->dma_addr,
 					 snd_pcm_lib_buffer_bytes(substream),
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 19f7896..1922ec5 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -798,10 +798,8 @@
 			mod_parse(src);
 			mod_parse(dvc);
 
-			if (playback)
-				of_node_put(playback);
-			if (capture)
-				of_node_put(capture);
+			of_node_put(playback);
+			of_node_put(capture);
 		}
 
 		dai_i++;
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c
index 488f9be..32eb6da 100644
--- a/sound/soc/sh/siu_pcm.c
+++ b/sound/soc/sh/siu_pcm.c
@@ -139,7 +139,7 @@
 
 	desc->callback = siu_dma_tx_complete;
 	desc->callback_param = siu_stream;
-	cookie = desc->tx_submit(desc);
+	cookie = dmaengine_submit(desc);
 	if (cookie < 0) {
 		dev_err(dev, "Failed to submit a dma transfer\n");
 		return cookie;
@@ -189,7 +189,7 @@
 
 	desc->callback = siu_dma_tx_complete;
 	desc->callback_param = siu_stream;
-	cookie = desc->tx_submit(desc);
+	cookie = dmaengine_submit(desc);
 	if (cookie < 0) {
 		dev_err(dev, "Failed to submit dma descriptor\n");
 		return cookie;
diff --git a/sound/soc/sirf/sirf-usp.c b/sound/soc/sirf/sirf-usp.c
index 3a73037..186dc7f 100644
--- a/sound/soc/sirf/sirf-usp.c
+++ b/sound/soc/sirf/sirf-usp.c
@@ -100,6 +100,16 @@
 		return -EINVAL;
 	}
 
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		usp->daifmt_format |= (fmt & SND_SOC_DAIFMT_INV_MASK);
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -177,7 +187,7 @@
 
 	shifter_len = data_len;
 
-	switch (usp->daifmt_format) {
+	switch (usp->daifmt_format & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
 		regmap_update_bits(usp->regmap, USP_RX_FRAME_CTRL,
 			USP_I2S_SYNC_CHG, USP_I2S_SYNC_CHG);
@@ -193,6 +203,18 @@
 		return -EINVAL;
 	}
 
+	switch (usp->daifmt_format & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		regmap_update_bits(usp->regmap, USP_MODE1,
+			USP_RXD_ACT_EDGE_FALLING | USP_TXD_ACT_EDGE_FALLING,
+			USP_RXD_ACT_EDGE_FALLING);
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		regmap_update_bits(usp->regmap, USP_TX_FRAME_CTRL,
 			USP_TXC_DATA_LEN_MASK | USP_TXC_FRAME_LEN_MASK
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index d074aa9..4c8f8a2 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -270,79 +270,54 @@
 	.llseek = default_llseek,
 };
 
-static struct dentry *soc_debugfs_create_dir(struct dentry *parent,
-	const char *fmt, ...)
+static void soc_init_component_debugfs(struct snd_soc_component *component)
 {
-	struct dentry *de;
-	va_list ap;
-	char *s;
+	if (component->debugfs_prefix) {
+		char *name;
 
-	va_start(ap, fmt);
-	s = kvasprintf(GFP_KERNEL, fmt, ap);
-	va_end(ap);
+		name = kasprintf(GFP_KERNEL, "%s:%s",
+			component->debugfs_prefix, component->name);
+		if (name) {
+			component->debugfs_root = debugfs_create_dir(name,
+				component->card->debugfs_card_root);
+			kfree(name);
+		}
+	} else {
+		component->debugfs_root = debugfs_create_dir(component->name,
+				component->card->debugfs_card_root);
+	}
 
-	if (!s)
-		return NULL;
-
-	de = debugfs_create_dir(s, parent);
-	kfree(s);
-
-	return de;
-}
-
-static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
-{
-	struct dentry *debugfs_card_root = codec->component.card->debugfs_card_root;
-
-	codec->debugfs_codec_root = soc_debugfs_create_dir(debugfs_card_root,
-						"codec:%s",
-						codec->component.name);
-	if (!codec->debugfs_codec_root) {
-		dev_warn(codec->dev,
-			"ASoC: Failed to create codec debugfs directory\n");
+	if (!component->debugfs_root) {
+		dev_warn(component->dev,
+			"ASoC: Failed to create component debugfs directory\n");
 		return;
 	}
 
-	debugfs_create_bool("cache_sync", 0444, codec->debugfs_codec_root,
+	snd_soc_dapm_debugfs_init(snd_soc_component_get_dapm(component),
+		component->debugfs_root);
+
+	if (component->init_debugfs)
+		component->init_debugfs(component);
+}
+
+static void soc_cleanup_component_debugfs(struct snd_soc_component *component)
+{
+	debugfs_remove_recursive(component->debugfs_root);
+}
+
+static void soc_init_codec_debugfs(struct snd_soc_component *component)
+{
+	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+
+	debugfs_create_bool("cache_sync", 0444, codec->component.debugfs_root,
 			    &codec->cache_sync);
-	debugfs_create_bool("cache_only", 0444, codec->debugfs_codec_root,
-			    &codec->cache_only);
 
 	codec->debugfs_reg = debugfs_create_file("codec_reg", 0644,
-						 codec->debugfs_codec_root,
+						 codec->component.debugfs_root,
 						 codec, &codec_reg_fops);
 	if (!codec->debugfs_reg)
 		dev_warn(codec->dev,
 			"ASoC: Failed to create codec register debugfs file\n");
-
-	snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root);
-}
-
-static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
-{
-	debugfs_remove_recursive(codec->debugfs_codec_root);
-}
-
-static void soc_init_platform_debugfs(struct snd_soc_platform *platform)
-{
-	struct dentry *debugfs_card_root = platform->component.card->debugfs_card_root;
-
-	platform->debugfs_platform_root = soc_debugfs_create_dir(debugfs_card_root,
-						"platform:%s",
-						platform->component.name);
-	if (!platform->debugfs_platform_root) {
-		dev_warn(platform->dev,
-			"ASoC: Failed to create platform debugfs directory\n");
-		return;
-	}
-
-	snd_soc_dapm_debugfs_init(&platform->component.dapm,
-		platform->debugfs_platform_root);
-}
-
-static void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform)
-{
-	debugfs_remove_recursive(platform->debugfs_platform_root);
 }
 
 static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
@@ -474,19 +449,15 @@
 
 #else
 
-static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec)
+#define soc_init_codec_debugfs NULL
+
+static inline void soc_init_component_debugfs(
+	struct snd_soc_component *component)
 {
 }
 
-static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
-{
-}
-
-static inline void soc_init_platform_debugfs(struct snd_soc_platform *platform)
-{
-}
-
-static inline void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform)
+static inline void soc_cleanup_component_debugfs(
+	struct snd_soc_component *component)
 {
 }
 
@@ -579,10 +550,8 @@
 	struct snd_soc_codec *codec;
 	int i, j;
 
-	/* If the initialization of this soc device failed, there is no codec
-	 * associated with it. Just bail out in this case.
-	 */
-	if (list_empty(&card->codec_dev_list))
+	/* If the card is not initialized yet there is nothing to do */
+	if (!card->instantiated)
 		return 0;
 
 	/* Due to the resume being scheduled into a workqueue we could
@@ -668,7 +637,7 @@
 	list_for_each_entry(codec, &card->codec_dev_list, card_list) {
 		/* If there are paths active then the CODEC will be held with
 		 * bias _ON and should not be suspended. */
-		if (!codec->suspended && codec->driver->suspend) {
+		if (!codec->suspended) {
 			switch (codec->dapm.bias_level) {
 			case SND_SOC_BIAS_STANDBY:
 				/*
@@ -682,8 +651,10 @@
 						"ASoC: idle_bias_off CODEC on over suspend\n");
 					break;
 				}
+
 			case SND_SOC_BIAS_OFF:
-				codec->driver->suspend(codec);
+				if (codec->driver->suspend)
+					codec->driver->suspend(codec);
 				codec->suspended = 1;
 				codec->cache_sync = 1;
 				if (codec->component.regmap)
@@ -757,11 +728,12 @@
 		 * left with bias OFF or STANDBY and suspended so we must now
 		 * resume.  Otherwise the suspend was suppressed.
 		 */
-		if (codec->driver->resume && codec->suspended) {
+		if (codec->suspended) {
 			switch (codec->dapm.bias_level) {
 			case SND_SOC_BIAS_STANDBY:
 			case SND_SOC_BIAS_OFF:
-				codec->driver->resume(codec);
+				if (codec->driver->resume)
+					codec->driver->resume(codec);
 				codec->suspended = 0;
 				break;
 			default:
@@ -835,10 +807,8 @@
 	struct snd_soc_card *card = dev_get_drvdata(dev);
 	int i, ac97_control = 0;
 
-	/* If the initialization of this soc device failed, there is no codec
-	 * associated with it. Just bail out in this case.
-	 */
-	if (list_empty(&card->codec_dev_list))
+	/* If the card is not initialized yet there is nothing to do */
+	if (!card->instantiated)
 		return 0;
 
 	/* activate pins from sleep state */
@@ -887,35 +857,40 @@
 static const struct snd_soc_dai_ops null_dai_ops = {
 };
 
-static struct snd_soc_codec *soc_find_codec(
-					const struct device_node *codec_of_node,
-					const char *codec_name)
+static struct snd_soc_component *soc_find_component(
+	const struct device_node *of_node, const char *name)
 {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 
-	list_for_each_entry(codec, &codec_list, list) {
-		if (codec_of_node) {
-			if (codec->dev->of_node != codec_of_node)
-				continue;
-		} else {
-			if (strcmp(codec->component.name, codec_name))
-				continue;
+	list_for_each_entry(component, &component_list, list) {
+		if (of_node) {
+			if (component->dev->of_node == of_node)
+				return component;
+		} else if (strcmp(component->name, name) == 0) {
+			return component;
 		}
-
-		return codec;
 	}
 
 	return NULL;
 }
 
-static struct snd_soc_dai *soc_find_codec_dai(struct snd_soc_codec *codec,
-					      const char *codec_dai_name)
+static struct snd_soc_dai *snd_soc_find_dai(
+	const struct snd_soc_dai_link_component *dlc)
 {
-	struct snd_soc_dai *codec_dai;
+	struct snd_soc_component *component;
+	struct snd_soc_dai *dai;
 
-	list_for_each_entry(codec_dai, &codec->component.dai_list, list) {
-		if (!strcmp(codec_dai->name, codec_dai_name)) {
-			return codec_dai;
+	/* Find CPU DAI from registered DAIs*/
+	list_for_each_entry(component, &component_list, list) {
+		if (dlc->of_node && component->dev->of_node != dlc->of_node)
+			continue;
+		if (dlc->name && strcmp(dev_name(component->dev), dlc->name))
+			continue;
+		list_for_each_entry(dai, &component->dai_list, list) {
+			if (dlc->dai_name && strcmp(dai->name, dlc->dai_name))
+				continue;
+
+			return dai;
 		}
 	}
 
@@ -926,33 +901,19 @@
 {
 	struct snd_soc_dai_link *dai_link = &card->dai_link[num];
 	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
-	struct snd_soc_component *component;
 	struct snd_soc_dai_link_component *codecs = dai_link->codecs;
+	struct snd_soc_dai_link_component cpu_dai_component;
 	struct snd_soc_dai **codec_dais = rtd->codec_dais;
 	struct snd_soc_platform *platform;
-	struct snd_soc_dai *cpu_dai;
 	const char *platform_name;
 	int i;
 
 	dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num);
 
-	/* Find CPU DAI from registered DAIs*/
-	list_for_each_entry(component, &component_list, list) {
-		if (dai_link->cpu_of_node &&
-			component->dev->of_node != dai_link->cpu_of_node)
-			continue;
-		if (dai_link->cpu_name &&
-			strcmp(dev_name(component->dev), dai_link->cpu_name))
-			continue;
-		list_for_each_entry(cpu_dai, &component->dai_list, list) {
-			if (dai_link->cpu_dai_name &&
-				strcmp(cpu_dai->name, dai_link->cpu_dai_name))
-				continue;
-
-			rtd->cpu_dai = cpu_dai;
-		}
-	}
-
+	cpu_dai_component.name = dai_link->cpu_name;
+	cpu_dai_component.of_node = dai_link->cpu_of_node;
+	cpu_dai_component.dai_name = dai_link->cpu_dai_name;
+	rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component);
 	if (!rtd->cpu_dai) {
 		dev_err(card->dev, "ASoC: CPU DAI %s not registered\n",
 			dai_link->cpu_dai_name);
@@ -963,15 +924,7 @@
 
 	/* Find CODEC from registered CODECs */
 	for (i = 0; i < rtd->num_codecs; i++) {
-		struct snd_soc_codec *codec;
-		codec = soc_find_codec(codecs[i].of_node, codecs[i].name);
-		if (!codec) {
-			dev_err(card->dev, "ASoC: CODEC %s not registered\n",
-				codecs[i].name);
-			return -EPROBE_DEFER;
-		}
-
-		codec_dais[i] = soc_find_codec_dai(codec, codecs[i].dai_name);
+		codec_dais[i] = snd_soc_find_dai(&codecs[i]);
 		if (!codec_dais[i]) {
 			dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n",
 				codecs[i].dai_name);
@@ -1012,68 +965,46 @@
 	return 0;
 }
 
-static int soc_remove_platform(struct snd_soc_platform *platform)
+static void soc_remove_component(struct snd_soc_component *component)
 {
-	int ret;
+	if (!component->probed)
+		return;
 
-	if (platform->driver->remove) {
-		ret = platform->driver->remove(platform);
-		if (ret < 0)
-			dev_err(platform->dev, "ASoC: failed to remove %d\n",
-				ret);
-	}
+	/* This is a HACK and will be removed soon */
+	if (component->codec)
+		list_del(&component->codec->card_list);
 
-	/* Make sure all DAPM widgets are freed */
-	snd_soc_dapm_free(&platform->component.dapm);
+	if (component->remove)
+		component->remove(component);
 
-	soc_cleanup_platform_debugfs(platform);
-	platform->probed = 0;
-	module_put(platform->dev->driver->owner);
+	snd_soc_dapm_free(snd_soc_component_get_dapm(component));
 
-	return 0;
+	soc_cleanup_component_debugfs(component);
+	component->probed = 0;
+	module_put(component->dev->driver->owner);
 }
 
-static void soc_remove_codec(struct snd_soc_codec *codec)
+static void soc_remove_dai(struct snd_soc_dai *dai, int order)
 {
 	int err;
 
-	if (codec->driver->remove) {
-		err = codec->driver->remove(codec);
-		if (err < 0)
-			dev_err(codec->dev, "ASoC: failed to remove %d\n", err);
-	}
-
-	/* Make sure all DAPM widgets are freed */
-	snd_soc_dapm_free(&codec->dapm);
-
-	soc_cleanup_codec_debugfs(codec);
-	codec->probed = 0;
-	list_del(&codec->card_list);
-	module_put(codec->dev->driver->owner);
-}
-
-static void soc_remove_codec_dai(struct snd_soc_dai *codec_dai, int order)
-{
-	int err;
-
-	if (codec_dai && codec_dai->probed &&
-			codec_dai->driver->remove_order == order) {
-		if (codec_dai->driver->remove) {
-			err = codec_dai->driver->remove(codec_dai);
+	if (dai && dai->probed &&
+			dai->driver->remove_order == order) {
+		if (dai->driver->remove) {
+			err = dai->driver->remove(dai);
 			if (err < 0)
-				dev_err(codec_dai->dev,
+				dev_err(dai->dev,
 					"ASoC: failed to remove %s: %d\n",
-					codec_dai->name, err);
+					dai->name, err);
 		}
-		codec_dai->probed = 0;
+		dai->probed = 0;
 	}
 }
 
 static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
 {
 	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	int i, err;
+	int i;
 
 	/* unregister the rtd device */
 	if (rtd->dev_registered) {
@@ -1085,22 +1016,9 @@
 
 	/* remove the CODEC DAI */
 	for (i = 0; i < rtd->num_codecs; i++)
-		soc_remove_codec_dai(rtd->codec_dais[i], order);
+		soc_remove_dai(rtd->codec_dais[i], order);
 
-	/* remove the cpu_dai */
-	if (cpu_dai && cpu_dai->probed &&
-			cpu_dai->driver->remove_order == order) {
-		if (cpu_dai->driver->remove) {
-			err = cpu_dai->driver->remove(cpu_dai);
-			if (err < 0)
-				dev_err(cpu_dai->dev,
-					"ASoC: failed to remove %s: %d\n",
-					cpu_dai->name, err);
-		}
-		cpu_dai->probed = 0;
-		if (!cpu_dai->codec)
-			module_put(cpu_dai->dev->driver->owner);
-	}
+	soc_remove_dai(rtd->cpu_dai, order);
 }
 
 static void soc_remove_link_components(struct snd_soc_card *card, int num,
@@ -1109,29 +1027,24 @@
 	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct snd_soc_platform *platform = rtd->platform;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	int i;
 
 	/* remove the platform */
-	if (platform && platform->probed &&
-	    platform->driver->remove_order == order) {
-		soc_remove_platform(platform);
-	}
+	if (platform && platform->component.driver->remove_order == order)
+		soc_remove_component(&platform->component);
 
 	/* remove the CODEC-side CODEC */
 	for (i = 0; i < rtd->num_codecs; i++) {
-		codec = rtd->codec_dais[i]->codec;
-		if (codec && codec->probed &&
-		    codec->driver->remove_order == order)
-			soc_remove_codec(codec);
+		component = rtd->codec_dais[i]->component;
+		if (component->driver->remove_order == order)
+			soc_remove_component(component);
 	}
 
 	/* remove any CPU-side CODEC */
 	if (cpu_dai) {
-		codec = cpu_dai->codec;
-		if (codec && codec->probed &&
-		    codec->driver->remove_order == order)
-			soc_remove_codec(codec);
+		if (cpu_dai->component->driver->remove_order == order)
+			soc_remove_component(cpu_dai->component);
 	}
 }
 
@@ -1173,137 +1086,78 @@
 	}
 }
 
-static int soc_probe_codec(struct snd_soc_card *card,
-			   struct snd_soc_codec *codec)
+static int soc_probe_component(struct snd_soc_card *card,
+	struct snd_soc_component *component)
 {
-	int ret = 0;
-	const struct snd_soc_codec_driver *driver = codec->driver;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	struct snd_soc_dai *dai;
+	int ret;
 
-	codec->component.card = card;
-	codec->dapm.card = card;
-	soc_set_name_prefix(card, &codec->component);
+	if (component->probed)
+		return 0;
 
-	if (!try_module_get(codec->dev->driver->owner))
+	component->card = card;
+	dapm->card = card;
+	soc_set_name_prefix(card, component);
+
+	if (!try_module_get(component->dev->driver->owner))
 		return -ENODEV;
 
-	soc_init_codec_debugfs(codec);
+	soc_init_component_debugfs(component);
 
-	if (driver->dapm_widgets) {
-		ret = snd_soc_dapm_new_controls(&codec->dapm,
-						driver->dapm_widgets,
-					 	driver->num_dapm_widgets);
+	if (component->dapm_widgets) {
+		ret = snd_soc_dapm_new_controls(dapm, component->dapm_widgets,
+			component->num_dapm_widgets);
 
 		if (ret != 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to create new controls %d\n", ret);
 			goto err_probe;
 		}
 	}
 
-	/* Create DAPM widgets for each DAI stream */
-	list_for_each_entry(dai, &codec->component.dai_list, list) {
-		ret = snd_soc_dapm_new_dai_widgets(&codec->dapm, dai);
-
+	list_for_each_entry(dai, &component->dai_list, list) {
+		ret = snd_soc_dapm_new_dai_widgets(dapm, dai);
 		if (ret != 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to create DAI widgets %d\n", ret);
 			goto err_probe;
 		}
 	}
 
-	codec->dapm.idle_bias_off = driver->idle_bias_off;
-
-	if (driver->probe) {
-		ret = driver->probe(codec);
+	if (component->probe) {
+		ret = component->probe(component);
 		if (ret < 0) {
-			dev_err(codec->dev,
-				"ASoC: failed to probe CODEC %d\n", ret);
+			dev_err(component->dev,
+				"ASoC: failed to probe component %d\n", ret);
 			goto err_probe;
 		}
-		WARN(codec->dapm.idle_bias_off &&
-			codec->dapm.bias_level != SND_SOC_BIAS_OFF,
+
+		WARN(dapm->idle_bias_off &&
+			dapm->bias_level != SND_SOC_BIAS_OFF,
 			"codec %s can not start from non-off bias with idle_bias_off==1\n",
-			codec->component.name);
+			component->name);
 	}
 
-	if (driver->controls)
-		snd_soc_add_codec_controls(codec, driver->controls,
-				     driver->num_controls);
-	if (driver->dapm_routes)
-		snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes,
-					driver->num_dapm_routes);
+	if (component->controls)
+		snd_soc_add_component_controls(component, component->controls,
+				     component->num_controls);
+	if (component->dapm_routes)
+		snd_soc_dapm_add_routes(dapm, component->dapm_routes,
+					component->num_dapm_routes);
 
-	/* mark codec as probed and add to card codec list */
-	codec->probed = 1;
-	list_add(&codec->card_list, &card->codec_dev_list);
-	list_add(&codec->dapm.list, &card->dapm_list);
+	component->probed = 1;
+	list_add(&dapm->list, &card->dapm_list);
+
+	/* This is a HACK and will be removed soon */
+	if (component->codec)
+		list_add(&component->codec->card_list, &card->codec_dev_list);
 
 	return 0;
 
 err_probe:
-	soc_cleanup_codec_debugfs(codec);
-	module_put(codec->dev->driver->owner);
-
-	return ret;
-}
-
-static int soc_probe_platform(struct snd_soc_card *card,
-			   struct snd_soc_platform *platform)
-{
-	int ret = 0;
-	const struct snd_soc_platform_driver *driver = platform->driver;
-	struct snd_soc_component *component;
-	struct snd_soc_dai *dai;
-
-	platform->component.card = card;
-	platform->component.dapm.card = card;
-
-	if (!try_module_get(platform->dev->driver->owner))
-		return -ENODEV;
-
-	soc_init_platform_debugfs(platform);
-
-	if (driver->dapm_widgets)
-		snd_soc_dapm_new_controls(&platform->component.dapm,
-			driver->dapm_widgets, driver->num_dapm_widgets);
-
-	/* Create DAPM widgets for each DAI stream */
-	list_for_each_entry(component, &component_list, list) {
-		if (component->dev != platform->dev)
-			continue;
-		list_for_each_entry(dai, &component->dai_list, list)
-			snd_soc_dapm_new_dai_widgets(&platform->component.dapm,
-				dai);
-	}
-
-	platform->component.dapm.idle_bias_off = 1;
-
-	if (driver->probe) {
-		ret = driver->probe(platform);
-		if (ret < 0) {
-			dev_err(platform->dev,
-				"ASoC: failed to probe platform %d\n", ret);
-			goto err_probe;
-		}
-	}
-
-	if (driver->controls)
-		snd_soc_add_platform_controls(platform, driver->controls,
-				     driver->num_controls);
-	if (driver->dapm_routes)
-		snd_soc_dapm_add_routes(&platform->component.dapm,
-			driver->dapm_routes, driver->num_dapm_routes);
-
-	/* mark platform as probed and add to card platform list */
-	platform->probed = 1;
-	list_add(&platform->component.dapm.list, &card->dapm_list);
-
-	return 0;
-
-err_probe:
-	soc_cleanup_platform_debugfs(platform);
-	module_put(platform->dev->driver->owner);
+	soc_cleanup_component_debugfs(component);
+	module_put(component->dev->driver->owner);
 
 	return ret;
 }
@@ -1342,17 +1196,21 @@
 	}
 	rtd->dev_registered = 1;
 
-	/* add DAPM sysfs entries for this codec */
-	ret = snd_soc_dapm_sys_add(rtd->dev);
-	if (ret < 0)
-		dev_err(rtd->dev,
-			"ASoC: failed to add codec dapm sysfs entries: %d\n", ret);
+	if (rtd->codec) {
+		/* add DAPM sysfs entries for this codec */
+		ret = snd_soc_dapm_sys_add(rtd->dev);
+		if (ret < 0)
+			dev_err(rtd->dev,
+				"ASoC: failed to add codec dapm sysfs entries: %d\n",
+				ret);
 
-	/* add codec sysfs entries */
-	ret = device_create_file(rtd->dev, &dev_attr_codec_reg);
-	if (ret < 0)
-		dev_err(rtd->dev,
-			"ASoC: failed to add codec sysfs files: %d\n", ret);
+		/* add codec sysfs entries */
+		ret = device_create_file(rtd->dev, &dev_attr_codec_reg);
+		if (ret < 0)
+			dev_err(rtd->dev,
+				"ASoC: failed to add codec sysfs files: %d\n",
+				ret);
+	}
 
 	return 0;
 }
@@ -1361,33 +1219,31 @@
 				     int order)
 {
 	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct snd_soc_platform *platform = rtd->platform;
+	struct snd_soc_component *component;
 	int i, ret;
 
 	/* probe the CPU-side component, if it is a CODEC */
-	if (cpu_dai->codec &&
-	    !cpu_dai->codec->probed &&
-	    cpu_dai->codec->driver->probe_order == order) {
-		ret = soc_probe_codec(card, cpu_dai->codec);
+	component = rtd->cpu_dai->component;
+	if (component->driver->probe_order == order) {
+		ret = soc_probe_component(card, component);
 		if (ret < 0)
 			return ret;
 	}
 
 	/* probe the CODEC-side components */
 	for (i = 0; i < rtd->num_codecs; i++) {
-		if (!rtd->codec_dais[i]->codec->probed &&
-		    rtd->codec_dais[i]->codec->driver->probe_order == order) {
-			ret = soc_probe_codec(card, rtd->codec_dais[i]->codec);
+		component = rtd->codec_dais[i]->component;
+		if (component->driver->probe_order == order) {
+			ret = soc_probe_component(card, component);
 			if (ret < 0)
 				return ret;
 		}
 	}
 
 	/* probe the platform */
-	if (!platform->probed &&
-	    platform->driver->probe_order == order) {
-		ret = soc_probe_platform(card, platform);
+	if (platform->component.driver->probe_order == order) {
+		ret = soc_probe_component(card, &platform->component);
 		if (ret < 0)
 			return ret;
 	}
@@ -1482,18 +1338,12 @@
 	/* probe the cpu_dai */
 	if (!cpu_dai->probed &&
 			cpu_dai->driver->probe_order == order) {
-		if (!cpu_dai->codec) {
-			if (!try_module_get(cpu_dai->dev->driver->owner))
-				return -ENODEV;
-		}
-
 		if (cpu_dai->driver->probe) {
 			ret = cpu_dai->driver->probe(cpu_dai);
 			if (ret < 0) {
 				dev_err(cpu_dai->dev,
 					"ASoC: failed to probe CPU DAI %s: %d\n",
 					cpu_dai->name, ret);
-				module_put(cpu_dai->dev->driver->owner);
 				return ret;
 			}
 		}
@@ -1654,17 +1504,24 @@
 {
 	struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
 	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
-	const char *codecname = aux_dev->codec_name;
+	const char *name = aux_dev->codec_name;
 
-	rtd->codec = soc_find_codec(aux_dev->codec_of_node, codecname);
-	if (!rtd->codec) {
+	rtd->component = soc_find_component(aux_dev->codec_of_node, name);
+	if (!rtd->component) {
 		if (aux_dev->codec_of_node)
-			codecname = of_node_full_name(aux_dev->codec_of_node);
+			name = of_node_full_name(aux_dev->codec_of_node);
 
-		dev_err(card->dev, "ASoC: %s not registered\n", codecname);
+		dev_err(card->dev, "ASoC: %s not registered\n", name);
 		return -EPROBE_DEFER;
 	}
 
+	/*
+	 * Some places still reference rtd->codec, so we have to keep that
+	 * initialized if the component is a CODEC. Once all those references
+	 * have been removed, this code can be removed as well.
+	 */
+	 rtd->codec = rtd->component->codec;
+
 	return 0;
 }
 
@@ -1674,18 +1531,13 @@
 	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
 	int ret;
 
-	if (rtd->codec->probed) {
-		dev_err(rtd->codec->dev, "ASoC: codec already probed\n");
-		return -EBUSY;
-	}
-
-	ret = soc_probe_codec(card, rtd->codec);
+	ret = soc_probe_component(card, rtd->component);
 	if (ret < 0)
 		return ret;
 
 	/* do machine specific initialization */
 	if (aux_dev->init) {
-		ret = aux_dev->init(&rtd->codec->dapm);
+		ret = aux_dev->init(rtd->component);
 		if (ret < 0) {
 			dev_err(card->dev, "ASoC: failed to init %s: %d\n",
 				aux_dev->name, ret);
@@ -1699,7 +1551,7 @@
 static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
 {
 	struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_component *component = rtd->component;
 
 	/* unregister the rtd device */
 	if (rtd->dev_registered) {
@@ -1708,8 +1560,8 @@
 		rtd->dev_registered = 0;
 	}
 
-	if (codec && codec->probed)
-		soc_remove_codec(codec);
+	if (component && component->probed)
+		soc_remove_component(component);
 }
 
 static int snd_soc_init_codec_cache(struct snd_soc_codec *codec)
@@ -2107,19 +1959,14 @@
 int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
 	struct snd_ac97_bus_ops *ops, int num)
 {
-	mutex_lock(&codec->mutex);
-
 	codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL);
-	if (codec->ac97 == NULL) {
-		mutex_unlock(&codec->mutex);
+	if (codec->ac97 == NULL)
 		return -ENOMEM;
-	}
 
 	codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL);
 	if (codec->ac97->bus == NULL) {
 		kfree(codec->ac97);
 		codec->ac97 = NULL;
-		mutex_unlock(&codec->mutex);
 		return -ENOMEM;
 	}
 
@@ -2132,7 +1979,6 @@
 	 */
 	codec->ac97_created = 1;
 
-	mutex_unlock(&codec->mutex);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
@@ -2302,7 +2148,6 @@
  */
 void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)
 {
-	mutex_lock(&codec->mutex);
 #ifdef CONFIG_SND_SOC_AC97_BUS
 	soc_unregister_ac97_codec(codec);
 #endif
@@ -2310,7 +2155,6 @@
 	kfree(codec->ac97);
 	codec->ac97 = NULL;
 	codec->ac97_created = 0;
-	mutex_unlock(&codec->mutex);
 }
 EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
 
@@ -3027,9 +2871,10 @@
 	unsigned int val, val_mask;
 	int ret;
 
-	val = ((ucontrol->value.integer.value[0] + min) & mask);
 	if (invert)
-		val = max - val;
+		val = (max - ucontrol->value.integer.value[0]) & mask;
+	else
+		val = ((ucontrol->value.integer.value[0] + min) & mask);
 	val_mask = mask << shift;
 	val = val << shift;
 
@@ -3038,9 +2883,10 @@
 		return ret;
 
 	if (snd_soc_volsw_is_stereo(mc)) {
-		val = ((ucontrol->value.integer.value[1] + min) & mask);
 		if (invert)
-			val = max - val;
+			val = (max - ucontrol->value.integer.value[1]) & mask;
+		else
+			val = ((ucontrol->value.integer.value[1] + min) & mask);
 		val_mask = mask << shift;
 		val = val << shift;
 
@@ -3085,8 +2931,9 @@
 	if (invert)
 		ucontrol->value.integer.value[0] =
 			max - ucontrol->value.integer.value[0];
-	ucontrol->value.integer.value[0] =
-		ucontrol->value.integer.value[0] - min;
+	else
+		ucontrol->value.integer.value[0] =
+			ucontrol->value.integer.value[0] - min;
 
 	if (snd_soc_volsw_is_stereo(mc)) {
 		ret = snd_soc_component_read(component, rreg, &val);
@@ -3097,8 +2944,9 @@
 		if (invert)
 			ucontrol->value.integer.value[1] =
 				max - ucontrol->value.integer.value[1];
-		ucontrol->value.integer.value[1] =
-			ucontrol->value.integer.value[1] - min;
+		else
+			ucontrol->value.integer.value[1] =
+				ucontrol->value.integer.value[1] - min;
 	}
 
 	return 0;
@@ -3928,8 +3776,11 @@
  */
 int snd_soc_unregister_card(struct snd_soc_card *card)
 {
-	if (card->instantiated)
+	if (card->instantiated) {
+		card->instantiated = false;
+		snd_soc_dapm_shutdown(card);
 		soc_cleanup_card_resources(card);
+	}
 	dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name);
 
 	return 0;
@@ -4116,6 +3967,8 @@
 
 	component->dev = dev;
 	component->driver = driver;
+	component->probe = component->driver->probe;
+	component->remove = component->driver->remove;
 
 	if (!component->dapm_ptr)
 		component->dapm_ptr = &component->dapm;
@@ -4124,19 +3977,42 @@
 	dapm->dev = dev;
 	dapm->component = component;
 	dapm->bias_level = SND_SOC_BIAS_OFF;
+	dapm->idle_bias_off = true;
 	if (driver->seq_notifier)
 		dapm->seq_notifier = snd_soc_component_seq_notifier;
 	if (driver->stream_event)
 		dapm->stream_event = snd_soc_component_stream_event;
 
+	component->controls = driver->controls;
+	component->num_controls = driver->num_controls;
+	component->dapm_widgets = driver->dapm_widgets;
+	component->num_dapm_widgets = driver->num_dapm_widgets;
+	component->dapm_routes = driver->dapm_routes;
+	component->num_dapm_routes = driver->num_dapm_routes;
+
 	INIT_LIST_HEAD(&component->dai_list);
 	mutex_init(&component->io_mutex);
 
 	return 0;
 }
 
+static void snd_soc_component_init_regmap(struct snd_soc_component *component)
+{
+	if (!component->regmap)
+		component->regmap = dev_get_regmap(component->dev, NULL);
+	if (component->regmap) {
+		int val_bytes = regmap_get_val_bytes(component->regmap);
+		/* Errors are legitimate for non-integer byte multiples */
+		if (val_bytes > 0)
+			component->val_bytes = val_bytes;
+	}
+}
+
 static void snd_soc_component_add_unlocked(struct snd_soc_component *component)
 {
+	if (!component->write && !component->read)
+		snd_soc_component_init_regmap(component);
+
 	list_add(&component->list, &component_list);
 }
 
@@ -4225,22 +4101,18 @@
 }
 EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
 
-static int snd_soc_platform_drv_write(struct snd_soc_component *component,
-	unsigned int reg, unsigned int val)
+static int snd_soc_platform_drv_probe(struct snd_soc_component *component)
 {
 	struct snd_soc_platform *platform = snd_soc_component_to_platform(component);
 
-	return platform->driver->write(platform, reg, val);
+	return platform->driver->probe(platform);
 }
 
-static int snd_soc_platform_drv_read(struct snd_soc_component *component,
-	unsigned int reg, unsigned int *val)
+static void snd_soc_platform_drv_remove(struct snd_soc_component *component)
 {
 	struct snd_soc_platform *platform = snd_soc_component_to_platform(component);
 
-	*val = platform->driver->read(platform, reg);
-
-	return 0;
+	platform->driver->remove(platform);
 }
 
 /**
@@ -4261,10 +4133,15 @@
 
 	platform->dev = dev;
 	platform->driver = platform_drv;
-	if (platform_drv->write)
-		platform->component.write = snd_soc_platform_drv_write;
-	if (platform_drv->read)
-		platform->component.read = snd_soc_platform_drv_read;
+
+	if (platform_drv->probe)
+		platform->component.probe = snd_soc_platform_drv_probe;
+	if (platform_drv->remove)
+		platform->component.remove = snd_soc_platform_drv_remove;
+
+#ifdef CONFIG_DEBUG_FS
+	platform->component.debugfs_prefix = "platform";
+#endif
 
 	mutex_lock(&client_mutex);
 	snd_soc_component_add_unlocked(&platform->component);
@@ -4315,10 +4192,10 @@
 	snd_soc_component_del_unlocked(&platform->component);
 	mutex_unlock(&client_mutex);
 
-	snd_soc_component_cleanup(&platform->component);
-
 	dev_dbg(platform->dev, "ASoC: Unregistered platform '%s'\n",
 		platform->component.name);
+
+	snd_soc_component_cleanup(&platform->component);
 }
 EXPORT_SYMBOL_GPL(snd_soc_remove_platform);
 
@@ -4386,6 +4263,20 @@
 			stream->formats |= codec_format_map[i];
 }
 
+static int snd_soc_codec_drv_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+
+	return codec->driver->probe(codec);
+}
+
+static void snd_soc_codec_drv_remove(struct snd_soc_component *component)
+{
+	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+
+	codec->driver->remove(codec);
+}
+
 static int snd_soc_codec_drv_write(struct snd_soc_component *component,
 	unsigned int reg, unsigned int val)
 {
@@ -4424,7 +4315,6 @@
 {
 	struct snd_soc_codec *codec;
 	struct snd_soc_dai *dai;
-	struct regmap *regmap;
 	int ret, i;
 
 	dev_dbg(dev, "codec register %s\n", dev_name(dev));
@@ -4434,18 +4324,37 @@
 		return -ENOMEM;
 
 	codec->component.dapm_ptr = &codec->dapm;
+	codec->component.codec = codec;
 
 	ret = snd_soc_component_initialize(&codec->component,
 			&codec_drv->component_driver, dev);
 	if (ret)
 		goto err_free;
 
+	if (codec_drv->controls) {
+		codec->component.controls = codec_drv->controls;
+		codec->component.num_controls = codec_drv->num_controls;
+	}
+	if (codec_drv->dapm_widgets) {
+		codec->component.dapm_widgets = codec_drv->dapm_widgets;
+		codec->component.num_dapm_widgets = codec_drv->num_dapm_widgets;
+	}
+	if (codec_drv->dapm_routes) {
+		codec->component.dapm_routes = codec_drv->dapm_routes;
+		codec->component.num_dapm_routes = codec_drv->num_dapm_routes;
+	}
+
+	if (codec_drv->probe)
+		codec->component.probe = snd_soc_codec_drv_probe;
+	if (codec_drv->remove)
+		codec->component.remove = snd_soc_codec_drv_remove;
 	if (codec_drv->write)
 		codec->component.write = snd_soc_codec_drv_write;
 	if (codec_drv->read)
 		codec->component.read = snd_soc_codec_drv_read;
 	codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;
-	codec->dapm.codec = codec;
+	codec->dapm.idle_bias_off = codec_drv->idle_bias_off;
+	codec->dapm.suspend_bias_off = codec_drv->suspend_bias_off;
 	if (codec_drv->seq_notifier)
 		codec->dapm.seq_notifier = codec_drv->seq_notifier;
 	if (codec_drv->set_bias_level)
@@ -4455,23 +4364,13 @@
 	codec->component.val_bytes = codec_drv->reg_word_size;
 	mutex_init(&codec->mutex);
 
-	if (!codec->component.write) {
-		if (codec_drv->get_regmap)
-			regmap = codec_drv->get_regmap(dev);
-		else
-			regmap = dev_get_regmap(dev, NULL);
+#ifdef CONFIG_DEBUG_FS
+	codec->component.init_debugfs = soc_init_codec_debugfs;
+	codec->component.debugfs_prefix = "codec";
+#endif
 
-		if (regmap) {
-			ret = snd_soc_component_init_io(&codec->component,
-				regmap);
-			if (ret) {
-				dev_err(codec->dev,
-						"Failed to set cache I/O:%d\n",
-						ret);
-				goto err_cleanup;
-			}
-		}
-	}
+	if (codec_drv->get_regmap)
+		codec->component.regmap = codec_drv->get_regmap(dev);
 
 	for (i = 0; i < num_dai; i++) {
 		fixup_codec_formats(&dai_drv[i].playback);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 177bd86..c61cb9c 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -326,12 +326,13 @@
 	list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
 		list_kcontrol)
 
-static unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
+unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
 {
 	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
 
 	return data->value;
 }
+EXPORT_SYMBOL_GPL(dapm_kcontrol_get_value);
 
 static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
 	unsigned int value)
@@ -591,9 +592,9 @@
 	int shared;
 	struct snd_kcontrol *kcontrol;
 	bool wname_in_long_name, kcname_in_long_name;
-	char *long_name;
+	char *long_name = NULL;
 	const char *name;
-	int ret;
+	int ret = 0;
 
 	prefix = soc_dapm_prefix(dapm);
 	if (prefix)
@@ -652,15 +653,17 @@
 
 		kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name,
 					prefix);
-		kfree(long_name);
-		if (!kcontrol)
-			return -ENOMEM;
+		if (!kcontrol) {
+			ret = -ENOMEM;
+			goto exit_free;
+		}
+
 		kcontrol->private_free = dapm_kcontrol_free;
 
 		ret = dapm_kcontrol_data_alloc(w, kcontrol);
 		if (ret) {
 			snd_ctl_free_one(kcontrol);
-			return ret;
+			goto exit_free;
 		}
 
 		ret = snd_ctl_add(card, kcontrol);
@@ -668,17 +671,18 @@
 			dev_err(dapm->dev,
 				"ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
 				w->name, name, ret);
-			return ret;
+			goto exit_free;
 		}
 	}
 
 	ret = dapm_kcontrol_add_widget(kcontrol, w);
-	if (ret)
-		return ret;
+	if (ret == 0)
+		w->kcontrols[kci] = kcontrol;
 
-	w->kcontrols[kci] = kcontrol;
+exit_free:
+	kfree(long_name);
 
-	return 0;
+	return ret;
 }
 
 /* create new dapm mixer control */
@@ -1683,6 +1687,22 @@
 	}
 }
 
+static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
+{
+	if (dapm->idle_bias_off)
+		return true;
+
+	switch (snd_power_get_state(dapm->card->snd_card)) {
+	case SNDRV_CTL_POWER_D3hot:
+	case SNDRV_CTL_POWER_D3cold:
+		return dapm->suspend_bias_off;
+	default:
+		break;
+	}
+
+	return false;
+}
+
 /*
  * Scan each dapm widget for complete audio path.
  * A complete path is a route that has valid endpoints i.e.:-
@@ -1706,7 +1726,7 @@
 	trace_snd_soc_dapm_start(card);
 
 	list_for_each_entry(d, &card->dapm_list, list) {
-		if (d->idle_bias_off)
+		if (dapm_idle_bias_off(d))
 			d->target_bias_level = SND_SOC_BIAS_OFF;
 		else
 			d->target_bias_level = SND_SOC_BIAS_STANDBY;
@@ -1772,7 +1792,7 @@
 		if (d->target_bias_level > bias)
 			bias = d->target_bias_level;
 	list_for_each_entry(d, &card->dapm_list, list)
-		if (!d->idle_bias_off)
+		if (!dapm_idle_bias_off(d))
 			d->target_bias_level = bias;
 
 	trace_snd_soc_dapm_walk_done(card);
@@ -3109,7 +3129,8 @@
 	}
 
 	w->dapm = dapm;
-	w->codec = dapm->codec;
+	if (dapm->component)
+		w->codec = dapm->component->codec;
 	INIT_LIST_HEAD(&w->sources);
 	INIT_LIST_HEAD(&w->sinks);
 	INIT_LIST_HEAD(&w->list);
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
index 6307f85..b329b84 100644
--- a/sound/soc/soc-generic-dmaengine-pcm.c
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -336,10 +336,12 @@
 };
 
 static const struct snd_soc_platform_driver dmaengine_pcm_platform = {
+	.component_driver = {
+		.probe_order = SND_SOC_COMP_ORDER_LATE,
+	},
 	.ops		= &dmaengine_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[] = {
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c
index 7767fbd..9b39390 100644
--- a/sound/soc/soc-io.c
+++ b/sound/soc/soc-io.c
@@ -271,31 +271,3 @@
 	return snd_soc_component_write(&platform->component, reg, val);
 }
 EXPORT_SYMBOL_GPL(snd_soc_platform_write);
-
-/**
- * snd_soc_component_init_io() - Initialize regmap IO
- *
- * @component: component to initialize
- * @regmap: regmap instance to use for IO operations
- *
- * Return: 0 on success, a negative error code otherwise
- */
-int snd_soc_component_init_io(struct snd_soc_component *component,
-	struct regmap *regmap)
-{
-	int ret;
-
-	if (!regmap)
-		return -EINVAL;
-
-	ret = regmap_get_val_bytes(regmap);
-	/* Errors are legitimate for non-integer byte
-	 * multiples */
-	if (ret > 0)
-		component->val_bytes = ret;
-
-	component->regmap = regmap;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_component_init_io);
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 642c862..002311a 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -352,7 +352,7 @@
 	} else {
 		for (i = 0; i < rtd->num_codecs; i++) {
 			codec_dai = rtd->codec_dais[i];
-			if (codec_dai->driver->playback.sig_bits == 0) {
+			if (codec_dai->driver->capture.sig_bits == 0) {
 				bits = 0;
 				break;
 			}
diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c
index b86cd99..01921d7 100644
--- a/sound/soc/tegra/tegra_max98090.c
+++ b/sound/soc/tegra/tegra_max98090.c
@@ -42,6 +42,7 @@
 struct tegra_max98090 {
 	struct tegra_asoc_utils_data util_data;
 	int gpio_hp_det;
+	int gpio_mic_det;
 };
 
 static int tegra_max98090_asoc_hw_params(struct snd_pcm_substream *substream,
@@ -112,6 +113,22 @@
 	.invert = 1,
 };
 
+static struct snd_soc_jack tegra_max98090_mic_jack;
+
+static struct snd_soc_jack_pin tegra_max98090_mic_jack_pins[] = {
+	{
+		.pin = "Mic Jack",
+		.mask = SND_JACK_MICROPHONE,
+	},
+};
+
+static struct snd_soc_jack_gpio tegra_max98090_mic_jack_gpio = {
+	.name = "Mic detection",
+	.report = SND_JACK_MICROPHONE,
+	.debounce_time = 150,
+	.invert = 1,
+};
+
 static const struct snd_soc_dapm_widget tegra_max98090_dapm_widgets[] = {
 	SND_SOC_DAPM_HP("Headphones", NULL),
 	SND_SOC_DAPM_SPK("Speakers", NULL),
@@ -141,6 +158,19 @@
 					&tegra_max98090_hp_jack_gpio);
 	}
 
+	if (gpio_is_valid(machine->gpio_mic_det)) {
+		snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
+				 &tegra_max98090_mic_jack);
+		snd_soc_jack_add_pins(&tegra_max98090_mic_jack,
+				      ARRAY_SIZE(tegra_max98090_mic_jack_pins),
+				      tegra_max98090_mic_jack_pins);
+
+		tegra_max98090_mic_jack_gpio.gpio = machine->gpio_mic_det;
+		snd_soc_jack_add_gpios(&tegra_max98090_mic_jack,
+				       1,
+				       &tegra_max98090_mic_jack_gpio);
+	}
+
 	return 0;
 }
 
@@ -153,6 +183,11 @@
 					&tegra_max98090_hp_jack_gpio);
 	}
 
+	if (gpio_is_valid(machine->gpio_mic_det)) {
+		snd_soc_jack_free_gpios(&tegra_max98090_mic_jack, 1,
+					&tegra_max98090_mic_jack_gpio);
+	}
+
 	return 0;
 }
 
@@ -201,6 +236,11 @@
 	if (machine->gpio_hp_det == -EPROBE_DEFER)
 		return -EPROBE_DEFER;
 
+	machine->gpio_mic_det =
+			of_get_named_gpio(np, "nvidia,mic-det-gpios", 0);
+	if (machine->gpio_mic_det == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+
 	ret = snd_soc_of_parse_card_name(card, "nvidia,model");
 	if (ret)
 		goto err;
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c
index f0829de..cd71fd8 100644
--- a/sound/soc/txx9/txx9aclc.c
+++ b/sound/soc/txx9/txx9aclc.c
@@ -16,6 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
+#include <linux/dmaengine.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -137,7 +138,7 @@
 	}
 	desc->callback = txx9aclc_dma_complete;
 	desc->callback_param = dmadata;
-	desc->tx_submit(desc);
+	dmaengine_submit(desc);
 	return desc;
 }
 
@@ -160,7 +161,7 @@
 		void __iomem *base = drvdata->base;
 
 		spin_unlock_irqrestore(&dmadata->dma_lock, flags);
-		chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+		dmaengine_terminate_all(chan);
 		/* first time */
 		for (i = 0; i < NR_DMA_CHAIN; i++) {
 			desc = txx9aclc_dma_submit(dmadata,
@@ -169,7 +170,7 @@
 				return;
 		}
 		dmadata->dmacount = NR_DMA_CHAIN;
-		chan->device->device_issue_pending(chan);
+		dma_async_issue_pending(chan);
 		spin_lock_irqsave(&dmadata->dma_lock, flags);
 		__raw_writel(ctlbit, base + ACCTLEN);
 		dmadata->frag_count = NR_DMA_CHAIN % dmadata->frags;
@@ -188,7 +189,7 @@
 			dmadata->frag_count * dmadata->frag_bytes);
 		if (!desc)
 			return;
-		chan->device->device_issue_pending(chan);
+		dma_async_issue_pending(chan);
 
 		spin_lock_irqsave(&dmadata->dma_lock, flags);
 		dmadata->frag_count++;
@@ -266,7 +267,7 @@
 	struct dma_chan *chan = dmadata->dma_chan;
 
 	dmadata->frag_count = -1;
-	chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+	dmaengine_terminate_all(chan);
 	return 0;
 }
 
@@ -398,8 +399,7 @@
 		struct dma_chan *chan = dmadata->dma_chan;
 		if (chan) {
 			dmadata->frag_count = -1;
-			chan->device->device_control(chan,
-						     DMA_TERMINATE_ALL, 0);
+			dmaengine_terminate_all(chan);
 			dma_release_channel(chan);
 		}
 		dev->dmadata[i].dma_chan = NULL;
diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c
index 7103b09..2728447 100644
--- a/sound/usb/caiaq/audio.c
+++ b/sound/usb/caiaq/audio.c
@@ -816,6 +816,11 @@
 		return -EINVAL;
 	}
 
+	if (cdev->n_streams < 2) {
+		dev_err(dev, "bogus number of streams: %d\n", cdev->n_streams);
+		return -EINVAL;
+	}
+
 	ret = snd_pcm_new(cdev->chip.card, cdev->product_name, 0,
 			cdev->n_audio_out, cdev->n_audio_in, &cdev->pcm);
 
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index 7b166c2..69e93a9 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -1506,6 +1506,12 @@
 	PORT_INFO(vendor, product, num, name, 0, \
 		  SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \
 		  SNDRV_SEQ_PORT_TYPE_HARDWARE)
+#define GM_SYNTH_PORT(vendor, product, num, name, voices) \
+	PORT_INFO(vendor, product, num, name, voices, \
+		  SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \
+		  SNDRV_SEQ_PORT_TYPE_MIDI_GM | \
+		  SNDRV_SEQ_PORT_TYPE_HARDWARE | \
+		  SNDRV_SEQ_PORT_TYPE_SYNTHESIZER)
 #define ROLAND_SYNTH_PORT(vendor, product, num, name, voices) \
 	PORT_INFO(vendor, product, num, name, voices, \
 		  SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \
@@ -1525,6 +1531,11 @@
 		  SNDRV_SEQ_PORT_TYPE_MIDI_MT32 | \
 		  SNDRV_SEQ_PORT_TYPE_HARDWARE | \
 		  SNDRV_SEQ_PORT_TYPE_SYNTHESIZER)
+	/* Yamaha MOTIF XF */
+	GM_SYNTH_PORT(0x0499, 0x105c, 0, "%s Tone Generator", 128),
+	CONTROL_PORT(0x0499, 0x105c, 1, "%s Remote Control"),
+	EXTERNAL_PORT(0x0499, 0x105c, 2, "%s Thru"),
+	CONTROL_PORT(0x0499, 0x105c, 3, "%s Editor"),
 	/* Roland UA-100 */
 	CONTROL_PORT(0x0582, 0x0000, 2, "%s Control"),
 	/* Roland SC-8850 */
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 2e4a9db..63a8adb 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1290,9 +1290,8 @@
 						    kctl->id.name,
 						    sizeof(kctl->id.name), 1);
 			if (!len)
-				len = snprintf(kctl->id.name,
-					       sizeof(kctl->id.name),
-					       "Feature %d", unitid);
+				snprintf(kctl->id.name, sizeof(kctl->id.name),
+					 "Feature %d", unitid);
 		}
 
 		if (!mapped_name)
@@ -1305,9 +1304,9 @@
 		 */
 		if (!mapped_name && !(state->oterm.type >> 16)) {
 			if ((state->oterm.type & 0xff00) == 0x0100)
-				len = append_ctl_name(kctl, " Capture");
+				append_ctl_name(kctl, " Capture");
 			else
-				len = append_ctl_name(kctl, " Playback");
+				append_ctl_name(kctl, " Playback");
 		}
 		append_ctl_name(kctl, control == UAC_FU_MUTE ?
 				" Switch" : " Volume");
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 223c47b..c657752 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -385,6 +385,36 @@
 	}
 },
 {
+	USB_DEVICE(0x0499, 0x1509),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		/* .vendor_name = "Yamaha", */
+		/* .product_name = "Steinberg UR22", */
+		.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 = 4,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
+				.ifnum = -1
+			}
+		}
+	}
+},
+{
 	USB_DEVICE(0x0499, 0x150a),
 	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
 		/* .vendor_name = "Yamaha", */
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 19a921e..d2aa45a 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1174,5 +1174,21 @@
 		}
 	}
 
+	/* XMOS based USB DACs */
+	switch (chip->usb_id) {
+	/* iFi Audio micro/nano iDSD */
+	case USB_ID(0x20b1, 0x3008):
+		if (fp->altsetting == 2)
+			return SNDRV_PCM_FMTBIT_DSD_U32_LE;
+		break;
+	/* DIYINHK DSD DXD 384kHz USB to I2S/DSD */
+	case USB_ID(0x20b1, 0x2009):
+		if (fp->altsetting == 3)
+			return SNDRV_PCM_FMTBIT_DSD_U32_LE;
+		break;
+	default:
+		break;
+	}
+
 	return 0;
 }