Merge tag 'sound-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound updates from Takashi Iwai:
 "Again the diffstat shows a widely distributed pattern at this cycle,
  as there've been many code cleanups and refactoring allover the
  places. Other than that, the development was relatively calm, and no
  big surprise shouldn't be expected. Here are some highlights:

  Core:
   - Sequencer code refactoring / documentation updates
   - TLV code moved to uapi, following some relevant cleanups

  USB-Audio:
   - Lots of LINE6 driver fixes / updates
   - DragonFly and TEAC device quirk updates

  HD-audio:
   - Usual fixupes for Dell, Lenovo and HP machines
   - Link-audio time reporting capability

  ASoC:
   - Large refactoring of simple-card code to be shared with rcar driver
   - Removal of some duplicated ops over lots of CODEC drivers
   - Again quite a few Intel SKL driver updates
   - New drivers for Nuvoton NAU88C10, Realtek RT5660 and RT5663"

* tag 'sound-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (465 commits)
  ASoC: fsl: Fix lockups with recent cache changes
  ASoC: Intel: Skylake: fix memory leak of module on error exit path
  ASoC: rsnd: add SNDRV_PCM_TRIGGER_SUSPEND/RESUME
  ASoC: wm8960: remove usage of obsoleted TLV-related macro
  ASoC: rt5616: remove usage of obsoleted TLV-related macro
  ASoC: max9867: remove usage of obsoleted TLV-related macro
  ASoC: trivial: system spelling fix
  ASoC: da7219: fix inappropriate condition statement
  ASoC: tlv320aic31xx: do not declare support for mono DAI
  ASoC: stac9766: fix wrong usage of DECLARE_TLV_DB_LINEAR()
  ASoC: wm8991: remove unused variable
  ASoC: wm8991: fix wrong usage of DECLARE_TLV_DB_LINEAR()
  ASOC: tpa6130a2: add static qualifier for file local symbols
  ASoC: sst-bxt-rt298: fix obsoleted initializers for array
  ASoC: sst-bxt-da7219_max98357a: fix obsoleted initializers for array
  ASoC: rt5616: add static qualifier for file local symbols
  ASoC: arizona: Add output power up/down delays for speaker path
  ASoC: arizona: Add debug prints for output power up/down times
  ALSA: hda - Add the top speaker pin config for HP Spectre x360
  ASoC: Intel: Add DMIC channel constraint for bxt machine
  ...
diff --git a/Documentation/devicetree/bindings/sound/nau8810.txt b/Documentation/devicetree/bindings/sound/nau8810.txt
new file mode 100644
index 0000000..05830e4
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nau8810.txt
@@ -0,0 +1,16 @@
+NAU8810 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+  - compatible : "nuvoton,nau8810"
+
+  - reg : the I2C address of the device.
+
+Example:
+
+codec: nau8810@1a {
+	compatible = "nuvoton,nau8810";
+	reg = <0x1a>;
+};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-sgtl5000.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-sgtl5000.txt
new file mode 100644
index 0000000..5da7da4
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-sgtl5000.txt
@@ -0,0 +1,42 @@
+NVIDIA Tegra audio complex, with SGTL5000 CODEC
+
+Required properties:
+- compatible : "nvidia,tegra-audio-sgtl5000"
+- clocks : Must contain an entry for each entry in clock-names.
+  See ../clocks/clock-bindings.txt for details.
+- clock-names : Must include the following entries:
+  - pll_a
+  - pll_a_out0
+  - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk)
+- nvidia,model : The user-visible name of this sound complex.
+- nvidia,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 for sources and
+  sinks are the SGTL5000's pins (as documented in its binding), and the jacks
+  on the board:
+
+  * Headphone Jack
+  * Line In Jack
+  * Mic Jack
+
+- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's
+  connected to the CODEC.
+- nvidia,audio-codec : The phandle of the SGTL5000 audio codec.
+
+Example:
+
+sound {
+	compatible = "toradex,tegra-audio-sgtl5000-apalis_t30",
+		     "nvidia,tegra-audio-sgtl5000";
+	nvidia,model = "Toradex Apalis T30";
+	nvidia,audio-routing =
+		"Headphone Jack", "HP_OUT",
+		"LINE_IN", "Line In Jack",
+		"MIC_IN", "Mic Jack";
+	nvidia,i2s-controller = <&tegra_i2s2>;
+	nvidia,audio-codec = <&sgtl5000>;
+	clocks = <&tegra_car TEGRA30_CLK_PLL_A>,
+		 <&tegra_car TEGRA30_CLK_PLL_A_OUT0>,
+		 <&tegra_car TEGRA30_CLK_EXTERN1>;
+	clock-names = "pll_a", "pll_a_out0", "mclk";
+};
diff --git a/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt b/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt
index 4812936..d9d8635 100644
--- a/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt
+++ b/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt
@@ -16,6 +16,24 @@
 				* "spkr-iomux"
 - qcom,model		: Name of the sound card.
 
+- qcom,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, MicBias
+			  of msm8x16_wcd codec and the jacks on the board:
+
+			  Power supplies:
+			  * MIC BIAS External1
+			  * MIC BIAS External2
+			  * MIC BIAS Internal1
+			  * MIC BIAS Internal2
+
+			  Board connectors:
+			  * Headset Mic
+			  * Secondary Mic",
+			  * DMIC
+			  * Ext Spk
+
 Dai-link subnode properties and subnodes:
 
 Required dai-link subnodes:
@@ -37,6 +55,18 @@
 	reg-names = "mic-iomux", "spkr-iomux";
 	qcom,model = "DB410c";
 
+	qcom,audio-routing =
+		"MIC BIAS External1", "Handset Mic",
+		"MIC BIAS Internal2", "Headset Mic",
+		"MIC BIAS External1", "Secondary Mic",
+		"AMIC1", "MIC BIAS External1",
+		"AMIC2", "MIC BIAS Internal2",
+		"AMIC3", "MIC BIAS External1",
+		"DMIC1", "MIC BIAS Internal1",
+		"MIC BIAS Internal1", "Digital Mic1",
+		"DMIC2", "MIC BIAS Internal1",
+		"MIC BIAS Internal1", "Digital Mic2";
+
 	/* I2S - Internal codec */
 	internal-dai-link@0 {
 		cpu { /* PRIMARY */
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt
deleted file mode 100644
index 255ece3..0000000
--- a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt
+++ /dev/null
@@ -1,75 +0,0 @@
-Renesas Sampling Rate Convert Sound Card:
-
-Renesas Sampling Rate Convert Sound Card specifies audio DAI connections of SoC <-> codec.
-
-Required properties:
-
-- compatible				: "renesas,rsrc-card{,<board>}"
-					  Examples with boards are:
-					    - "renesas,rsrc-card"
-					    - "renesas,rsrc-card,lager"
-					    - "renesas,rsrc-card,koelsch"
-Optional properties:
-
-- card_name				: User specified audio sound card name, one string
-					  property.
-- cpu					: CPU   sub-node
-- codec					: CODEC sub-node
-
-Optional subnode properties:
-
-- format				: CPU/CODEC common audio format.
-					  "i2s", "right_j", "left_j" , "dsp_a"
-					  "dsp_b", "ac97", "pdm", "msb", "lsb"
-- frame-master				: Indicates dai-link frame master.
-					  phandle to a cpu or codec subnode.
-- bitclock-master			: Indicates dai-link bit clock master.
-					  phandle to a cpu or codec subnode.
-- bitclock-inversion			: bool property. Add this if the
-					  dai-link uses bit clock inversion.
-- frame-inversion			: bool property. Add this if the
-					  dai-link uses frame clock inversion.
-- convert-rate				: platform specified sampling rate convert
-- convert-channels			: platform specified converted channel size (2 - 8 ch)
-- audio-prefix				: see audio-routing
-- 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 for sources.
-					  use audio-prefix if some components is using same sink/sources naming.
-					  it can be used if compatible was "renesas,rsrc-card";
-
-Required CPU/CODEC subnodes properties:
-
-- sound-dai				: phandle and port of CPU/CODEC
-
-Optional CPU/CODEC subnodes properties:
-
-- clocks / system-clock-frequency	: specify subnode's clock if needed.
-					  it can be specified via "clocks" if system has
-					  clock node (= common clock), or "system-clock-frequency"
-					  (if system doens't support common clock)
-					  If a clock is specified, it is
-					  enabled with clk_prepare_enable()
-					  in dai startup() and disabled with
-					  clk_disable_unprepare() in dai
-					  shutdown().
-
-Example
-
-sound {
-	compatible = "renesas,rsrc-card,lager";
-
-	card-name = "rsnd-ak4643";
-	format = "left_j";
-	bitclock-master = <&sndcodec>;
-	frame-master = <&sndcodec>;
-
-	sndcpu: cpu {
-		sound-dai = <&rcar_sound>;
-	};
-
-	sndcodec: codec {
-		sound-dai = <&ak4643>;
-		system-clock-frequency = <11289600>;
-	};
-};
diff --git a/Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.txt b/Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.txt
new file mode 100644
index 0000000..eac91db
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.txt
@@ -0,0 +1,22 @@
+ROCKCHIP with MAX98357A/RT5514/DA7219 codecs on GRU boards
+
+Required properties:
+- compatible: "rockchip,rk3399-gru-sound"
+- rockchip,cpu: The phandle of the Rockchip I2S controller that's
+  connected to the codecs
+- rockchip,codec: The phandle of the MAX98357A/RT5514/DA7219 codecs
+
+Optional properties:
+- dmic-wakeup-delay-ms : specify delay time (ms) for DMIC ready.
+  If this option is specified, which means it's required dmic need
+  delay for DMIC to ready so that rt5514 can avoid recording before
+  DMIC send valid data
+
+Example:
+
+sound {
+	compatible = "rockchip,rk3399-gru-sound";
+	rockchip,cpu = <&i2s0>;
+	rockchip,codec = <&max98357a &rt5514 &da7219>;
+	dmic-wakeup-delay-ms = <20>;
+};
diff --git a/Documentation/devicetree/bindings/sound/rt5659.txt b/Documentation/devicetree/bindings/sound/rt5659.txt
index 5f79e7f..1766e05 100644
--- a/Documentation/devicetree/bindings/sound/rt5659.txt
+++ b/Documentation/devicetree/bindings/sound/rt5659.txt
@@ -12,6 +12,9 @@
 
 Optional properties:
 
+- clocks: The phandle of the master clock to the CODEC
+- clock-names: Should be "mclk"
+
 - realtek,in1-differential
 - realtek,in3-differential
 - realtek,in4-differential
diff --git a/Documentation/devicetree/bindings/sound/rt5660.txt b/Documentation/devicetree/bindings/sound/rt5660.txt
new file mode 100644
index 0000000..30be5f9
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rt5660.txt
@@ -0,0 +1,47 @@
+RT5660 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : "realtek,rt5660".
+
+- reg : The I2C address of the device.
+
+Optional properties:
+
+- clocks: The phandle of the master clock to the CODEC
+- clock-names: Should be "mclk"
+
+- realtek,in1-differential
+- realtek,in3-differential
+  Boolean. Indicate MIC1/3 input are differential, rather than single-ended.
+
+- realtek,poweroff-in-suspend
+  Boolean. If the codec will be powered off in suspend, the resume should be
+  added delay time for waiting codec power ready.
+
+- realtek,dmic1-data-pin
+  0: dmic1 is not used
+  1: using GPIO2 pin as dmic1 data pin
+  2: using IN1P pin as dmic1 data pin
+
+Pins on the device (for linking into audio routes) for RT5660:
+
+  * DMIC L1
+  * DMIC R1
+  * IN1P
+  * IN1N
+  * IN2P
+  * IN3P
+  * IN3N
+  * SPO
+  * LOUTL
+  * LOUTR
+
+Example:
+
+rt5660 {
+	compatible = "realtek,rt5660";
+	reg = <0x1c>;
+};
diff --git a/Documentation/devicetree/bindings/sound/rt5663.txt b/Documentation/devicetree/bindings/sound/rt5663.txt
new file mode 100644
index 0000000..7d3c974
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rt5663.txt
@@ -0,0 +1,30 @@
+RT5663/RT5668 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : One of "realtek,rt5663" or "realtek,rt5668".
+
+- reg : The I2C address of the device.
+
+- interrupts : The CODEC's interrupt output.
+
+Optional properties:
+
+Pins on the device (for linking into audio routes) for RT5663/RT5668:
+
+  * IN1P
+  * IN1N
+  * IN2P
+  * IN2N
+  * HPOL
+  * HPOR
+
+Example:
+
+codec: rt5663@12 {
+	compatible = "realtek,rt5663";
+	reg = <0x12>;
+	interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
+};
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt
index 59d8628..c7a9393 100644
--- a/Documentation/devicetree/bindings/sound/simple-card.txt
+++ b/Documentation/devicetree/bindings/sound/simple-card.txt
@@ -22,6 +22,8 @@
 					  headphones are attached.
 - simple-audio-card,mic-det-gpio	: Reference to GPIO that signals when
 					  a microphone is attached.
+- simple-audio-card,aux-devs		: List of phandles pointing to auxiliary devices, such
+					  as amplifiers, to be added to the sound card.
 
 Optional subnodes:
 
@@ -162,3 +164,38 @@
 		};
 	};
 };
+
+Example 3 - route audio from IMX6 SSI2 through TLV320DAC3100 codec
+through TPA6130A2 amplifier to headphones:
+
+&i2c0 {
+	codec: tlv320dac3100@18 {
+		compatible = "ti,tlv320dac3100";
+		...
+	}
+
+	amp: tpa6130a2@60 {
+		compatible = "ti,tpa6130a2";
+		...
+	}
+}
+
+sound {
+	compatible = "simple-audio-card";
+	...
+	simple-audio-card,widgets =
+		"Headphone", "Headphone Jack";
+	simple-audio-card,routing =
+		"Headphone Jack", "HPLEFT",
+		"Headphone Jack", "HPRIGHT",
+		"LEFTIN", "HPL",
+		"RIGHTIN", "HPR";
+	simple-audio-card,aux-devs = <&amp>;
+	simple-audio-card,cpu {
+		sound-dai = <&ssi2>;
+	};
+	simple-audio-card,codec {
+		sound-dai = <&codec>;
+		clocks = ...
+	};
+};
diff --git a/Documentation/devicetree/bindings/sound/simple-scu-card.txt b/Documentation/devicetree/bindings/sound/simple-scu-card.txt
new file mode 100644
index 0000000..d6fe47e
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/simple-scu-card.txt
@@ -0,0 +1,110 @@
+ASoC simple SCU Sound Card
+
+Simple-Card specifies audio DAI connections of SoC <-> codec.
+
+Required properties:
+
+- compatible				: "simple-scu-audio-card"
+					  "renesas,rsrc-card"
+
+Optional properties:
+
+- simple-audio-card,name		: User specified audio sound card name, one string
+					  property.
+- simple-audio-card,cpu			: CPU   sub-node
+- simple-audio-card,codec		: CODEC sub-node
+
+Optional subnode properties:
+
+- simple-audio-card,format		: CPU/CODEC common audio format.
+					  "i2s", "right_j", "left_j" , "dsp_a"
+					  "dsp_b", "ac97", "pdm", "msb", "lsb"
+- simple-audio-card,frame-master	: Indicates dai-link frame master.
+					  phandle to a cpu or codec subnode.
+- simple-audio-card,bitclock-master	: Indicates dai-link bit clock master.
+					  phandle to a cpu or codec subnode.
+- simple-audio-card,bitclock-inversion	: bool property. Add this if the
+					  dai-link uses bit clock inversion.
+- simple-audio-card,frame-inversion	: bool property. Add this if the
+					  dai-link uses frame clock inversion.
+- simple-audio-card,convert-rate	: platform specified sampling rate convert
+- simple-audio-card,convert-channels	: platform specified converted channel size (2 - 8 ch)
+- simple-audio-card,prefix		: see audio-routing
+- simple-audio-card,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 for sources.
+					  use audio-prefix if some components is using same sink/sources naming.
+					  it can be used if compatible was "renesas,rsrc-card";
+
+Required CPU/CODEC subnodes properties:
+
+- sound-dai				: phandle and port of CPU/CODEC
+
+Optional CPU/CODEC subnodes properties:
+
+- clocks / system-clock-frequency	: specify subnode's clock if needed.
+					  it can be specified via "clocks" if system has
+					  clock node (= common clock), or "system-clock-frequency"
+					  (if system doens't support common clock)
+					  If a clock is specified, it is
+					  enabled with clk_prepare_enable()
+					  in dai startup() and disabled with
+					  clk_disable_unprepare() in dai
+					  shutdown().
+
+Example 1. Sampling Rate Covert
+
+sound {
+	compatible = "simple-scu-audio-card";
+
+	simple-audio-card,name = "rsnd-ak4643";
+	simple-audio-card,format = "left_j";
+	simple-audio-card,format = "left_j";
+	simple-audio-card,bitclock-master = <&sndcodec>;
+	simple-audio-card,frame-master = <&sndcodec>;
+
+	simple-audio-card,convert-rate = <48000>; /* see audio_clk_a */
+
+	simple-audio-card,prefix = "ak4642";
+	simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
+			"DAI0 Capture", "ak4642 Capture";
+
+	sndcpu: simple-audio-card,cpu {
+		sound-dai = <&rcar_sound>;
+	};
+
+	sndcodec: simple-audio-card,codec {
+		sound-dai = <&ak4643>;
+		system-clock-frequency = <11289600>;
+	};
+};
+
+Example 2. 2 CPU 1 Codec
+
+sound {
+	compatible = "renesas,rsrc-card";
+
+	card-name = "rsnd-ak4643";
+	format = "left_j";
+	bitclock-master = <&dpcmcpu>;
+	frame-master = <&dpcmcpu>;
+
+	convert-rate = <48000>;  /* see audio_clk_a */
+
+	audio-prefix = "ak4642";
+	audio-routing = "ak4642 Playback", "DAI0 Playback",
+			"ak4642 Playback", "DAI1 Playback";
+
+	dpcmcpu: cpu@0 {
+		sound-dai = <&rcar_sound 0>;
+	};
+
+	cpu@1 {
+		sound-dai = <&rcar_sound 1>;
+	};
+
+	codec {
+		sound-dai = <&ak4643>;
+		clocks = <&audio_clock>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt b/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt
index 16bcdfb..745dc62 100644
--- a/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt
+++ b/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt
@@ -11,7 +11,9 @@
 ---------------------------------------
 
 Required properties:
-  - compatible: "st,sti-uni-player" or "st,sti-uni-reader"
+  - compatible: "st,stih407-uni-player-hdmi", "st,stih407-uni-player-pcm-out",
+		"st,stih407-uni-player-dac", "st,stih407-uni-player-spdif",
+		"st,stih407-uni-reader-pcm_in", "st,stih407-uni-reader-hdmi",
 
   - st,syscfg: phandle to boot-device system configuration registers
 
@@ -33,32 +35,24 @@
 	"tx" for "st,sti-uni-player" compatibility
 	"rx" for "st,sti-uni-reader" compatibility
 
-  - st,version: IP version integrated in SOC.
-
-  - dai-name: DAI name that describes the IP.
-
-  - st,mode: IP working mode depending on associated codec.
-	"HDMI" connected to HDMI codec and support IEC HDMI formats (player only).
-	"SPDIF" connected to SPDIF codec and support SPDIF formats (player only).
-	"PCM" PCM standard mode for I2S or TDM bus.
-	"TDM" TDM mode for TDM bus.
-
 Required properties ("st,sti-uni-player" compatibility only):
   - clocks: CPU_DAI IP clock source, listed in the same order than the
 	    CPU_DAI properties.
 
-  - st,uniperiph-id: internal SOC IP instance ID.
-
 Optional properties:
   - pinctrl-0: defined for CPU_DAI@1 and CPU_DAI@4 to describe I2S PIOs for
 	       external codecs connection.
 
   - pinctrl-names: should contain only one value - "default".
 
+  - st,tdm-mode: to declare to set TDM mode for unireader and uniplayer IPs.
+	Only compartible with IPs in charge of the external I2S/TDM bus.
+	Should be declared depending on associated codec.
+
 Example:
 
-	sti_uni_player1: sti-uni-player@1 {
-		compatible = "st,sti-uni-player";
+	sti_uni_player1: sti-uni-player@0x8D81000 {
+		compatible = "st,stih407-uni-player-hdmi";
 		status = "okay";
 		#sound-dai-cells = <0>;
 		st,syscfg = <&syscfg_core>;
@@ -66,15 +60,12 @@
 		reg = <0x8D81000 0x158>;
 		interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>;
 		dmas = <&fdma0 3 0 1>;
-		st,dai-name = "Uni Player #1 (I2S)";
 		dma-names = "tx";
-		st,uniperiph-id = <1>;
-		st,version = <5>;
-		st,mode = "TDM";
+		st,tdm-mode = <1>;
 	};
 
-	sti_uni_player2: sti-uni-player@2 {
-		compatible = "st,sti-uni-player";
+	sti_uni_player2: sti-uni-player@0x8D82000 {
+		compatible = "st,stih407-uni-player-pcm-out";
 		status = "okay";
 		#sound-dai-cells = <0>;
 		st,syscfg = <&syscfg_core>;
@@ -82,15 +73,11 @@
 		reg = <0x8D82000 0x158>;
 		interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>;
 		dmas = <&fdma0 4 0 1>;
-		dai-name = "Uni Player #2 (DAC)";
 		dma-names = "tx";
-		st,uniperiph-id = <2>;
-		st,version = <5>;
-		st,mode = "PCM";
 	};
 
-	sti_uni_player3: sti-uni-player@3 {
-		compatible = "st,sti-uni-player";
+	sti_uni_player3: sti-uni-player@0x8D85000 {
+		compatible = "st,stih407-uni-player-spdif";
 		status = "okay";
 		#sound-dai-cells = <0>;
 		st,syscfg = <&syscfg_core>;
@@ -99,14 +86,10 @@
 		interrupts = <GIC_SPI 89 IRQ_TYPE_NONE>;
 		dmas = <&fdma0 7 0 1>;
 		dma-names = "tx";
-		dai-name = "Uni Player #3 (SPDIF)";
-		st,uniperiph-id = <3>;
-		st,version = <5>;
-		st,mode = "SPDIF";
 	};
 
-	sti_uni_reader1: sti-uni-reader@1 {
-		compatible = "st,sti-uni-reader";
+	sti_uni_reader1: sti-uni-reader@0x8D84000 {
+		compatible = "st,stih407-uni-reader-hdmi";
 		status = "disabled";
 		#sound-dai-cells = <0>;
 		st,syscfg = <&syscfg_core>;
@@ -114,9 +97,6 @@
 		interrupts = <GIC_SPI 88 IRQ_TYPE_NONE>;
 		dmas = <&fdma0 6 0 1>;
 		dma-names = "rx";
-		dai-name = "Uni Reader #1 (HDMI RX)";
-		st,version = <3>;
-		st,mode = "PCM";
 	};
 
 2) sti-sas-codec: internal audio codec IPs driver
diff --git a/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt b/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
index 13503aa..0230c4d 100644
--- a/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
+++ b/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
@@ -9,6 +9,7 @@
 
   - compatible		: should be one of the following:
     - "allwinner,sun4i-a10-spdif": for the Allwinner A10 SoC
+    - "allwinner,sun6i-a31-spdif": for the Allwinner A31 SoC
 
   - reg			: Offset and length of the register set for the device.
 
@@ -25,6 +26,8 @@
 	"apb"		  clock for the spdif bus.
 	"spdif"		  clock for spdif controller.
 
+  - resets		: reset specifier for the ahb reset (A31 and newer only)
+
 Example:
 
 spdif: spdif@01c21000 {
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
index eff12be..9340d2d 100644
--- a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
+++ b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
@@ -11,6 +11,7 @@
     "ti,tlv320aic3110" - TLV320AIC3110 (stereo speaker amp, no MiniDSP)
     "ti,tlv320aic3120" - TLV320AIC3120 (mono speaker amp, MiniDSP)
     "ti,tlv320aic3111" - TLV320AIC3111 (stereo speaker amp, MiniDSP)
+    "ti,tlv320dac3100" - TLV320DAC3100 (no ADC, mono speaker amp, no MiniDSP)
 
 - reg - <int> -  I2C slave address
 - HPVDD-supply, SPRVDD-supply, SPLVDD-supply, AVDD-supply, IOVDD-supply,
@@ -37,9 +38,11 @@
   * MICBIAS
 
 CODEC input pins:
-  * MIC1LP
-  * MIC1RP
-  * MIC1LM
+  * MIC1LP, devices with ADC
+  * MIC1RP, devices with ADC
+  * MIC1LM, devices with ADC
+  * AIN1, devices without ADC
+  * AIN2, devices without ADC
 
 The pins can be used in referring sound node's audio-routing property.
 
diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c
index a852168..13999c1 100644
--- a/arch/arm/mach-s3c24xx/mach-mini2440.c
+++ b/arch/arm/mach-s3c24xx/mach-mini2440.c
@@ -497,9 +497,28 @@
 	},
 };
 
+static struct uda134x_platform_data s3c24xx_uda134x = {
+	.l3 = {
+		.gpio_clk = S3C2410_GPB(4),
+		.gpio_data = S3C2410_GPB(3),
+		.gpio_mode = S3C2410_GPB(2),
+		.use_gpios = 1,
+		.data_hold = 1,
+		.data_setup = 1,
+		.clock_high = 1,
+		.mode_hold = 1,
+		.mode = 1,
+		.mode_setup = 1,
+	},
+	.model = UDA134X_UDA1341,
+};
+
 static struct platform_device uda1340_codec = {
 		.name = "uda134x-codec",
 		.id = -1,
+		.dev = {
+			.platform_data	= &s3c24xx_uda134x,
+		},
 };
 
 static struct platform_device *mini2440_devices[] __initdata = {
diff --git a/include/sound/da7219.h b/include/sound/da7219.h
index 02876ac..409ef139 100644
--- a/include/sound/da7219.h
+++ b/include/sound/da7219.h
@@ -34,6 +34,8 @@
 struct da7219_aad_pdata;
 
 struct da7219_pdata {
+	bool wakeup_source;
+
 	/* Mic */
 	enum da7219_micbias_voltage micbias_lvl;
 	enum da7219_mic_amp_in_sel mic_amp_in_sel;
diff --git a/include/sound/hda_register.h b/include/sound/hda_register.h
index ff1aecf..0013063 100644
--- a/include/sound/hda_register.h
+++ b/include/sound/hda_register.h
@@ -89,6 +89,19 @@
 #define AZX_REG_SD_BDLPL		0x18
 #define AZX_REG_SD_BDLPU		0x1c
 
+/* GTS registers */
+#define AZX_REG_LLCH			0x14
+
+#define AZX_REG_GTS_BASE		0x520
+
+#define AZX_REG_GTSCC	(AZX_REG_GTS_BASE + 0x00)
+#define AZX_REG_WALFCC	(AZX_REG_GTS_BASE + 0x04)
+#define AZX_REG_TSCCL	(AZX_REG_GTS_BASE + 0x08)
+#define AZX_REG_TSCCU	(AZX_REG_GTS_BASE + 0x0C)
+#define AZX_REG_LLPFOC	(AZX_REG_GTS_BASE + 0x14)
+#define AZX_REG_LLPCL	(AZX_REG_GTS_BASE + 0x18)
+#define AZX_REG_LLPCU	(AZX_REG_GTS_BASE + 0x1C)
+
 /* Haswell/Broadwell display HD-A controller Extended Mode registers */
 #define AZX_REG_HSW_EM4			0x100c
 #define AZX_REG_HSW_EM5			0x1010
@@ -242,6 +255,29 @@
 /* Interval used to calculate the iterating register offset */
 #define AZX_DRSM_INTERVAL		0x08
 
+/* Global time synchronization registers */
+#define GTSCC_TSCCD_MASK		0x80000000
+#define GTSCC_TSCCD_SHIFT		BIT(31)
+#define GTSCC_TSCCI_MASK		0x20
+#define GTSCC_CDMAS_DMA_DIR_SHIFT	4
+
+#define WALFCC_CIF_MASK			0x1FF
+#define WALFCC_FN_SHIFT			9
+#define HDA_CLK_CYCLES_PER_FRAME	512
+
+/*
+ * An error occurs near frame "rollover". The clocks in frame value indicates
+ * whether this error may have occurred. Here we use the value of 10. Please
+ * see the errata for the right number [<10]
+ */
+#define HDA_MAX_CYCLE_VALUE		499
+#define HDA_MAX_CYCLE_OFFSET		10
+#define HDA_MAX_CYCLE_READ_RETRY	10
+
+#define TSCCU_CCU_SHIFT			32
+#define LLPC_CCU_SHIFT			32
+
+
 /*
  * helpers to read the stream position
  */
diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
index 93e63c5..56004ec 100644
--- a/include/sound/hdaudio.h
+++ b/include/sound/hdaudio.h
@@ -245,6 +245,12 @@
 
 /*
  * HD-audio bus base driver
+ *
+ * @ppcap: pp capabilities pointer
+ * @spbcap: SPIB capabilities pointer
+ * @mlcap: MultiLink capabilities pointer
+ * @gtscap: gts capabilities pointer
+ * @drsmcap: dma resume capabilities pointer
  */
 struct hdac_bus {
 	struct device *dev;
@@ -256,6 +262,12 @@
 	void __iomem *remap_addr;
 	int irq;
 
+	void __iomem *ppcap;
+	void __iomem *spbcap;
+	void __iomem *mlcap;
+	void __iomem *gtscap;
+	void __iomem *drsmcap;
+
 	/* codec linked list */
 	struct list_head codec_list;
 	unsigned int num_codecs;
@@ -335,6 +347,7 @@
 int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val);
 int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
 			      unsigned int *res);
+int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus);
 int snd_hdac_link_power(struct hdac_device *codec, bool enable);
 
 bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset);
diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h
index b9593b2..8660a7f 100644
--- a/include/sound/hdaudio_ext.h
+++ b/include/sound/hdaudio_ext.h
@@ -8,11 +8,6 @@
  *
  * @bus: hdac bus
  * @num_streams: streams supported
- * @ppcap: pp capabilities pointer
- * @spbcap: SPIB capabilities pointer
- * @mlcap: MultiLink capabilities pointer
- * @gtscap: gts capabilities pointer
- * @drsmcap: dma resume capabilities pointer
  * @hlink_list: link list of HDA links
  * @lock: lock for link mgmt
  * @cmd_dma_state: state of cmd DMAs: CORB and RIRB
@@ -22,12 +17,6 @@
 	int num_streams;
 	int idx;
 
-	void __iomem *ppcap;
-	void __iomem *spbcap;
-	void __iomem *mlcap;
-	void __iomem *gtscap;
-	void __iomem *drsmcap;
-
 	struct list_head hlink_list;
 
 	struct mutex lock;
@@ -54,7 +43,6 @@
 #define HDA_CODEC_EXT_ENTRY(_vid, _revid, _name, _drv_data) \
 	HDA_CODEC_REV_EXT_ENTRY(_vid, _revid, _name, _drv_data)
 
-int snd_hdac_ext_bus_parse_capabilities(struct hdac_ext_bus *sbus);
 void snd_hdac_ext_bus_ppcap_enable(struct hdac_ext_bus *chip, bool enable);
 void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_ext_bus *chip, bool enable);
 
diff --git a/include/sound/l3.h b/include/sound/l3.h
index 423a08f..1471da2 100644
--- a/include/sound/l3.h
+++ b/include/sound/l3.h
@@ -2,9 +2,15 @@
 #define _L3_H_ 1
 
 struct l3_pins {
-	void (*setdat)(int);
-	void (*setclk)(int);
-	void (*setmode)(int);
+	void (*setdat)(struct l3_pins *, int);
+	void (*setclk)(struct l3_pins *, int);
+	void (*setmode)(struct l3_pins *, int);
+
+	int gpio_data;
+	int gpio_clk;
+	int gpio_mode;
+	int use_gpios;
+
 	int data_hold;
 	int data_setup;
 	int clock_high;
@@ -13,6 +19,9 @@
 	int mode_setup;
 };
 
+struct device;
+
 int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len);
+int l3_set_gpio_ops(struct device *dev, struct l3_pins *adap);
 
 #endif
diff --git a/include/sound/rt5660.h b/include/sound/rt5660.h
new file mode 100644
index 0000000..065f83a
--- /dev/null
+++ b/include/sound/rt5660.h
@@ -0,0 +1,31 @@
+/*
+ * linux/sound/rt5660.h -- Platform data for RT5660
+ *
+ * Copyright 2016 Realtek Semiconductor Corp.
+ * Author: Oder Chiou <oder_chiou@realtek.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 __LINUX_SND_RT5660_H
+#define __LINUX_SND_RT5660_H
+
+enum rt5660_dmic1_data_pin {
+	RT5660_DMIC1_NULL,
+	RT5660_DMIC1_DATA_GPIO2,
+	RT5660_DMIC1_DATA_IN1P,
+};
+
+struct rt5660_platform_data {
+	/* IN1 & IN3 can optionally be differential */
+	bool in1_diff;
+	bool in3_diff;
+	bool use_ldo2;
+	bool poweroff_codec_in_suspend;
+
+	enum rt5660_dmic1_data_pin dmic1_data_pin;
+};
+
+#endif
diff --git a/include/sound/s3c24xx_uda134x.h b/include/sound/s3c24xx_uda134x.h
index 33df4cb..ffaf1f0 100644
--- a/include/sound/s3c24xx_uda134x.h
+++ b/include/sound/s3c24xx_uda134x.h
@@ -7,7 +7,6 @@
 	int l3_clk;
 	int l3_mode;
 	int l3_data;
-	void (*power) (int);
 	int model;
 };
 
diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index 86088ae..fd641255 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -27,10 +27,45 @@
 				  struct device_node *codec,
 				  char *prefix,
 				  unsigned int *retfmt);
+__printf(3, 4)
 int asoc_simple_card_set_dailink_name(struct device *dev,
 				      struct snd_soc_dai_link *dai_link,
 				      const char *fmt, ...);
 int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
 				     char *prefix);
 
+#define asoc_simple_card_parse_clk_cpu(node, dai_link, simple_dai)		\
+	asoc_simple_card_parse_clk(node, dai_link->cpu_of_node, simple_dai)
+#define asoc_simple_card_parse_clk_codec(node, dai_link, simple_dai)		\
+	asoc_simple_card_parse_clk(node, dai_link->codec_of_node, simple_dai)
+int asoc_simple_card_parse_clk(struct device_node *node,
+			       struct device_node *dai_of_node,
+			       struct asoc_simple_dai *simple_dai);
+
+#define asoc_simple_card_parse_cpu(node, dai_link,				\
+				   list_name, cells_name, is_single_link)	\
+	asoc_simple_card_parse_dai(node, &dai_link->cpu_of_node,		\
+		&dai_link->cpu_dai_name, list_name, cells_name, is_single_link)
+#define asoc_simple_card_parse_codec(node, dai_link, list_name, cells_name)	\
+	asoc_simple_card_parse_dai(node, &dai_link->codec_of_node,		\
+		&dai_link->codec_dai_name, list_name, cells_name, NULL)
+#define asoc_simple_card_parse_platform(node, dai_link, list_name, cells_name)	\
+	asoc_simple_card_parse_dai(node, &dai_link->platform_of_node,		\
+		NULL, list_name, cells_name, NULL)
+int asoc_simple_card_parse_dai(struct device_node *node,
+				  struct device_node **endpoint_np,
+				  const char **dai_name,
+				  const char *list_name,
+				  const char *cells_name,
+				  int *is_single_links);
+
+int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
+			      struct asoc_simple_dai *simple_dai);
+
+int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link);
+void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
+				      int is_single_links);
+
+int asoc_simple_card_clean_reference(struct snd_soc_card *card);
+
 #endif /* __SIMPLE_CARD_CORE_H */
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 6144882..4f1c784 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -898,14 +898,6 @@
 	int (*resume)(struct snd_soc_codec *);
 	struct snd_soc_component_driver component_driver;
 
-	/* 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;
-
 	/* codec wide operations */
 	int (*set_sysclk)(struct snd_soc_codec *codec,
 			  int clk_id, int source, unsigned int freq, int dir);
@@ -1547,17 +1539,6 @@
 	return snd_soc_component_get_drvdata(&platform->component);
 }
 
-static inline void snd_soc_pcm_set_drvdata(struct snd_soc_pcm_runtime *rtd,
-		void *data)
-{
-	dev_set_drvdata(rtd->dev, data);
-}
-
-static inline void *snd_soc_pcm_get_drvdata(struct snd_soc_pcm_runtime *rtd)
-{
-	return dev_get_drvdata(rtd->dev);
-}
-
 static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card)
 {
 	INIT_LIST_HEAD(&card->codec_dev_list);
diff --git a/include/sound/tlv.h b/include/sound/tlv.h
index df97d19..3677ebb 100644
--- a/include/sound/tlv.h
+++ b/include/sound/tlv.h
@@ -22,67 +22,39 @@
  *
  */
 
-/*
- * TLV structure is right behind the struct snd_ctl_tlv:
- *   unsigned int type  	- see SNDRV_CTL_TLVT_*
- *   unsigned int length
- *   .... data aligned to sizeof(unsigned int), use
- *        block_length = (length + (sizeof(unsigned int) - 1)) &
- *                       ~(sizeof(unsigned int) - 1)) ....
- */
-
 #include <uapi/sound/tlv.h>
 
-#define TLV_ITEM(type, ...) \
-	(type), TLV_LENGTH(__VA_ARGS__), __VA_ARGS__
-#define TLV_LENGTH(...) \
-	((unsigned int)sizeof((const unsigned int[]) { __VA_ARGS__ }))
+/* For historical reasons, these macros are aliases to the ones in UAPI. */
+#define TLV_ITEM			SNDRV_CTL_TLVD_ITEM
+#define TLV_LENGTH			SNDRV_CTL_TLVD_LENGTH
 
-#define TLV_CONTAINER_ITEM(...) \
-	TLV_ITEM(SNDRV_CTL_TLVT_CONTAINER, __VA_ARGS__)
-#define DECLARE_TLV_CONTAINER(name, ...) \
-	unsigned int name[] = { TLV_CONTAINER_ITEM(__VA_ARGS__) }
+#define TLV_CONTAINER_ITEM		SNDRV_CTL_TLVD_CONTAINER_ITEM
+#define DECLARE_TLV_CONTAINER		SNDRV_CTL_TLVD_DECLARE_CONTAINER
 
-#define TLV_DB_SCALE_MASK	0xffff
-#define TLV_DB_SCALE_MUTE	0x10000
-#define TLV_DB_SCALE_ITEM(min, step, mute)			\
-	TLV_ITEM(SNDRV_CTL_TLVT_DB_SCALE,			\
-		 (min),					\
-		 ((step) & TLV_DB_SCALE_MASK) |		\
-			((mute) ? TLV_DB_SCALE_MUTE : 0))
-#define DECLARE_TLV_DB_SCALE(name, min, step, mute) \
-	unsigned int name[] = { TLV_DB_SCALE_ITEM(min, step, mute) }
+#define TLV_DB_SCALE_MASK		SNDRV_CTL_TLVD_DB_SCALE_MASK
+#define TLV_DB_SCALE_MUTE		SNDRV_CTL_TLVD_DB_SCALE_MUTE
+#define TLV_DB_SCALE_ITEM		SNDRV_CTL_TLVD_DB_SCALE_ITEM
+#define DECLARE_TLV_DB_SCALE		SNDRV_CTL_TLVD_DECLARE_DB_SCALE
 
-/* dB scale specified with min/max values instead of step */
-#define TLV_DB_MINMAX_ITEM(min_dB, max_dB)			\
-	TLV_ITEM(SNDRV_CTL_TLVT_DB_MINMAX, (min_dB), (max_dB))
-#define TLV_DB_MINMAX_MUTE_ITEM(min_dB, max_dB)			\
-	TLV_ITEM(SNDRV_CTL_TLVT_DB_MINMAX_MUTE, (min_dB), (max_dB))
-#define DECLARE_TLV_DB_MINMAX(name, min_dB, max_dB) \
-	unsigned int name[] = { TLV_DB_MINMAX_ITEM(min_dB, max_dB) }
-#define DECLARE_TLV_DB_MINMAX_MUTE(name, min_dB, max_dB) \
-	unsigned int name[] = { TLV_DB_MINMAX_MUTE_ITEM(min_dB, max_dB) }
+#define TLV_DB_MINMAX_ITEM		SNDRV_CTL_TLVD_DB_MINMAX_ITEM
+#define TLV_DB_MINMAX_MUTE_ITEM		SNDRV_CTL_TLVD_DB_MINMAX_MUTE_ITEM
+#define DECLARE_TLV_DB_MINMAX		SNDRV_CTL_TLVD_DECLARE_DB_MINMAX
+#define DECLARE_TLV_DB_MINMAX_MUTE	SNDRV_CTL_TLVD_DECLARE_DB_MINMAX_MUTE
 
-/* linear volume between min_dB and max_dB (.01dB unit) */
-#define TLV_DB_LINEAR_ITEM(min_dB, max_dB)		    \
-	TLV_ITEM(SNDRV_CTL_TLVT_DB_LINEAR, (min_dB), (max_dB))
-#define DECLARE_TLV_DB_LINEAR(name, min_dB, max_dB)	\
-	unsigned int name[] = { TLV_DB_LINEAR_ITEM(min_dB, max_dB) }
+#define TLV_DB_LINEAR_ITEM		SNDRV_CTL_TLVD_DB_LINEAR_ITEM
+#define DECLARE_TLV_DB_LINEAR		SNDRV_CTL_TLVD_DECLARE_DB_LINEAR
 
-/* dB range container:
- * Items in dB range container must be ordered by their values and by their
- * dB values. This implies that larger values must correspond with larger
- * dB values (which is also required for all other mixer controls).
+#define TLV_DB_RANGE_ITEM		SNDRV_CTL_TLVD_DB_RANGE_ITEM
+#define DECLARE_TLV_DB_RANGE		SNDRV_CTL_TLVD_DECLARE_DB_RANGE
+
+#define TLV_DB_GAIN_MUTE		SNDRV_CTL_TLVD_DB_GAIN_MUTE
+
+/*
+ * The below assumes that each item TLV is 4 words like DB_SCALE or LINEAR.
+ * This is an old fasion and obsoleted by commit bf1d1c9b6179("ALSA: tlv: add
+ * DECLARE_TLV_DB_RANGE()").
  */
-/* Each item is: <min> <max> <TLV> */
-#define TLV_DB_RANGE_ITEM(...) \
-	TLV_ITEM(SNDRV_CTL_TLVT_DB_RANGE, __VA_ARGS__)
-#define DECLARE_TLV_DB_RANGE(name, ...) \
-	unsigned int name[] = { TLV_DB_RANGE_ITEM(__VA_ARGS__) }
-/* The below assumes that each item TLV is 4 words like DB_SCALE or LINEAR */
-#define TLV_DB_RANGE_HEAD(num)			\
+#define TLV_DB_RANGE_HEAD(num) \
 	SNDRV_CTL_TLVT_DB_RANGE, 6 * (num) * sizeof(unsigned int)
 
-#define TLV_DB_GAIN_MUTE	-9999999
-
 #endif /* __SOUND_TLV_H */
diff --git a/include/uapi/sound/Kbuild b/include/uapi/sound/Kbuild
index 691984c..9578d8b 100644
--- a/include/uapi/sound/Kbuild
+++ b/include/uapi/sound/Kbuild
@@ -13,3 +13,4 @@
 header-y += sfnt_info.h
 header-y += tlv.h
 header-y += usb_stream.h
+header-y += snd_sst_tokens.h
diff --git a/include/uapi/sound/asoc.h b/include/uapi/sound/asoc.h
index e4701a3..33d00a4 100644
--- a/include/uapi/sound/asoc.h
+++ b/include/uapi/sound/asoc.h
@@ -83,7 +83,7 @@
 #define SND_SOC_TPLG_NUM_TEXTS		16
 
 /* ABI version */
-#define SND_SOC_TPLG_ABI_VERSION	0x4
+#define SND_SOC_TPLG_ABI_VERSION	0x5
 
 /* Max size of TLV data */
 #define SND_SOC_TPLG_TLV_SIZE		32
@@ -105,7 +105,8 @@
 #define SND_SOC_TPLG_TYPE_CODEC_LINK	9
 #define SND_SOC_TPLG_TYPE_BACKEND_LINK	10
 #define SND_SOC_TPLG_TYPE_PDATA		11
-#define SND_SOC_TPLG_TYPE_MAX	SND_SOC_TPLG_TYPE_PDATA
+#define SND_SOC_TPLG_TYPE_BE_DAI	12
+#define SND_SOC_TPLG_TYPE_MAX		SND_SOC_TPLG_TYPE_BE_DAI
 
 /* vendor block IDs - please add new vendor types to end */
 #define SND_SOC_TPLG_TYPE_VENDOR_FW	1000
@@ -124,6 +125,11 @@
 #define SND_SOC_TPLG_TUPLE_TYPE_WORD	4
 #define SND_SOC_TPLG_TUPLE_TYPE_SHORT	5
 
+/* BE DAI flags */
+#define SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES         (1 << 0)
+#define SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS      (1 << 1)
+#define SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS    (1 << 2)
+
 /*
  * Block Header.
  * This header precedes all object and object arrays below.
@@ -251,6 +257,7 @@
 	__le32 period_size_max;	/* max period size bytes */
 	__le32 buffer_size_min;	/* min buffer size bytes */
 	__le32 buffer_size_max;	/* max buffer size bytes */
+	__le32 sig_bits;        /* number of bits of content */
 } __attribute__((packed));
 
 /*
@@ -285,6 +292,8 @@
 	__le32 graph_elems;	/* number of graph elements */
 	__le32 pcm_elems;	/* number of PCM elements */
 	__le32 dai_link_elems;	/* number of DAI link elements */
+	__le32 be_dai_elems;	/* number of BE DAI elements */
+	__le32 reserved[20];	/* reserved for new ABI element types */
 	struct snd_soc_tplg_private priv;
 } __attribute__((packed));
 
@@ -450,4 +459,26 @@
 	struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* supported configs playback and captrure */
 	__le32 num_streams;     /* number of streams */
 } __attribute__((packed));
+
+/*
+ * Describes SW/FW specific features of BE DAI.
+ *
+ * File block representation for BE DAI :-
+ * +-----------------------------------+-----+
+ * | struct snd_soc_tplg_hdr           |  1  |
+ * +-----------------------------------+-----+
+ * | struct snd_soc_tplg_be_dai        |  N  |
+ * +-----------------------------------+-----+
+ */
+struct snd_soc_tplg_be_dai {
+	__le32 size;            /* in bytes of this structure */
+	char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* name - used to match */
+	__le32 dai_id;          /* unique ID - used to match */
+	__le32 playback;        /* supports playback mode */
+	__le32 capture;         /* supports capture mode */
+	struct snd_soc_tplg_stream_caps caps[2]; /* playback and capture for DAI */
+	__le32 flag_mask;       /* bitmask of flags to configure */
+	__le32 flags;           /* SND_SOC_TPLG_DAI_FLGBIT_* */
+	struct snd_soc_tplg_private priv;
+} __attribute__((packed));
 #endif
diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
index 609cadb..be353a7 100644
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
@@ -106,9 +106,10 @@
 	SNDRV_HWDEP_IFACE_FW_OXFW,	/* Oxford OXFW970/971 based device */
 	SNDRV_HWDEP_IFACE_FW_DIGI00X,	/* Digidesign Digi 002/003 family */
 	SNDRV_HWDEP_IFACE_FW_TASCAM,	/* TASCAM FireWire series */
+	SNDRV_HWDEP_IFACE_LINE6,	/* Line6 USB processors */
 
 	/* Don't forget to change the following: */
-	SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_TASCAM
+	SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_LINE6
 };
 
 struct snd_hwdep_info {
diff --git a/include/uapi/sound/snd_sst_tokens.h b/include/uapi/sound/snd_sst_tokens.h
new file mode 100644
index 0000000..1ee2e94
--- /dev/null
+++ b/include/uapi/sound/snd_sst_tokens.h
@@ -0,0 +1,214 @@
+/*
+ * snd_sst_tokens.h - Intel SST tokens definition
+ *
+ * Copyright (C) 2016 Intel Corp
+ * Author: Shreyas NC <shreyas.nc@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 version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+#ifndef __SND_SST_TOKENS_H__
+#define __SND_SST_TOKENS_H__
+
+/**
+ * %SKL_TKN_UUID:               Module UUID
+ *
+ * %SKL_TKN_U8_BLOCK_TYPE:      Type of the private data block.Can be:
+ *                              tuples, bytes, short and words
+ *
+ * %SKL_TKN_U8_IN_PIN_TYPE:     Input pin type,
+ *                              homogenous=0, heterogenous=1
+ *
+ * %SKL_TKN_U8_OUT_PIN_TYPE:    Output pin type,
+ *                              homogenous=0, heterogenous=1
+ * %SKL_TKN_U8_DYN_IN_PIN:      Configure Input pin dynamically
+ *                              if true
+ *
+ * %SKL_TKN_U8_DYN_OUT_PIN:     Configure Output pin dynamically
+ *                              if true
+ *
+ * %SKL_TKN_U8_IN_QUEUE_COUNT:  Store the number of Input pins
+ *
+ * %SKL_TKN_U8_OUT_QUEUE_COUNT: Store the number of Output pins
+ *
+ * %SKL_TKN_U8_TIME_SLOT:       TDM slot number
+ *
+ * %SKL_TKN_U8_CORE_ID:         Stores module affinity value.Can take
+ *                              the values:
+ *                              SKL_AFFINITY_CORE_0 = 0,
+ *                              SKL_AFFINITY_CORE_1,
+ *                              SKL_AFFINITY_CORE_MAX
+ *
+ * %SKL_TKN_U8_MOD_TYPE:        Module type value.
+ *
+ * %SKL_TKN_U8_CONN_TYPE:       Module connection type can be a FE,
+ *                              BE or NONE as defined :
+ *                              SKL_PIPE_CONN_TYPE_NONE = 0,
+ *                              SKL_PIPE_CONN_TYPE_FE = 1 (HOST_DMA)
+ *                              SKL_PIPE_CONN_TYPE_BE = 2 (LINK_DMA)
+ *
+ * %SKL_TKN_U8_DEV_TYPE:        Type of device to which the module is
+ *                              connected
+ *                              Can take the values:
+ *                              SKL_DEVICE_BT = 0x0,
+ *                              SKL_DEVICE_DMIC = 0x1,
+ *                              SKL_DEVICE_I2S = 0x2,
+ *                              SKL_DEVICE_SLIMBUS = 0x3,
+ *                              SKL_DEVICE_HDALINK = 0x4,
+ *                              SKL_DEVICE_HDAHOST = 0x5,
+ *                              SKL_DEVICE_NONE
+ *
+ * %SKL_TKN_U8_HW_CONN_TYPE:    Connection type of the HW to which the
+ *                              module is connected
+ *                              SKL_CONN_NONE = 0,
+ *                              SKL_CONN_SOURCE = 1,
+ *                              SKL_CONN_SINK = 2
+ *
+ * %SKL_TKN_U16_PIN_INST_ID:    Stores the pin instance id
+ *
+ * %SKL_TKN_U16_MOD_INST_ID:    Stores the mdule instance id
+ *
+ * %SKL_TKN_U32_MAX_MCPS:       Module max mcps value
+ *
+ * %SKL_TKN_U32_MEM_PAGES:      Module resource pages
+ *
+ * %SKL_TKN_U32_OBS:            Stores Output Buffer size
+ *
+ * %SKL_TKN_U32_IBS:            Stores input buffer size
+ *
+ * %SKL_TKN_U32_VBUS_ID:        Module VBUS_ID. PDM=0, SSP0=0,
+ *                              SSP1=1,SSP2=2,
+ *                              SSP3=3, SSP4=4,
+ *                              SSP5=5, SSP6=6,INVALID
+ *
+ * %SKL_TKN_U32_PARAMS_FIXUP:   Module Params fixup mask
+ * %SKL_TKN_U32_CONVERTER:      Module params converter mask
+ * %SKL_TKN_U32_PIPE_ID:        Stores the pipe id
+ *
+ * %SKL_TKN_U32_PIPE_CONN_TYPE: Type of the token to which the pipe is
+ *                              connected to. It can be
+ *                              SKL_PIPE_CONN_TYPE_NONE = 0,
+ *                              SKL_PIPE_CONN_TYPE_FE = 1 (HOST_DMA),
+ *                              SKL_PIPE_CONN_TYPE_BE = 2 (LINK_DMA),
+ *
+ * %SKL_TKN_U32_PIPE_PRIORITY:  Pipe priority value
+ * %SKL_TKN_U32_PIPE_MEM_PGS:   Pipe resource pages
+ *
+ * %SKL_TKN_U32_DIR_PIN_COUNT:  Value for the direction to set input/output
+ *                              formats and the pin count.
+ *                              The first 4 bits have the direction
+ *                              value and the next 4 have
+ *                              the pin count value.
+ *                              SKL_DIR_IN = 0, SKL_DIR_OUT = 1.
+ *                              The input and output formats
+ *                              share the same set of tokens
+ *                              with the distinction between input
+ *                              and output made by reading direction
+ *                              token.
+ *
+ * %SKL_TKN_U32_FMT_CH:         Supported channel count
+ *
+ * %SKL_TKN_U32_FMT_FREQ:       Supported frequency/sample rate
+ *
+ * %SKL_TKN_U32_FMT_BIT_DEPTH:  Supported container size
+ *
+ * %SKL_TKN_U32_FMT_SAMPLE_SIZE:Number of samples in the container
+ *
+ * %SKL_TKN_U32_FMT_CH_CONFIG:  Supported channel configurations for the
+ *                              input/output.
+ *
+ * %SKL_TKN_U32_FMT_INTERLEAVE: Interleaving style which can be per
+ *                              channel or per sample. The values can be :
+ *                              SKL_INTERLEAVING_PER_CHANNEL = 0,
+ *                              SKL_INTERLEAVING_PER_SAMPLE = 1,
+ *
+ * %SKL_TKN_U32_FMT_SAMPLE_TYPE:
+ *                              Specifies the sample type. Can take the
+ *                              values: SKL_SAMPLE_TYPE_INT_MSB = 0,
+ *                              SKL_SAMPLE_TYPE_INT_LSB = 1,
+ *                              SKL_SAMPLE_TYPE_INT_SIGNED = 2,
+ *                              SKL_SAMPLE_TYPE_INT_UNSIGNED = 3,
+ *                              SKL_SAMPLE_TYPE_FLOAT = 4
+ *
+ * %SKL_TKN_U32_CH_MAP:         Channel map values
+ * %SKL_TKN_U32_MOD_SET_PARAMS: It can take these values:
+ *                              SKL_PARAM_DEFAULT, SKL_PARAM_INIT,
+ *                              SKL_PARAM_SET, SKL_PARAM_BIND
+ *
+ * %SKL_TKN_U32_MOD_PARAM_ID:   ID of the module params
+ *
+ * %SKL_TKN_U32_CAPS_SET_PARAMS:
+ *                              Set params value
+ *
+ * %SKL_TKN_U32_CAPS_PARAMS_ID: Params ID
+ *
+ * %SKL_TKN_U32_CAPS_SIZE:      Caps size
+ *
+ * %SKL_TKN_U32_PROC_DOMAIN:    Specify processing domain
+ *
+ * %SKL_TKN_U32_LIB_COUNT:      Specifies the number of libraries
+ *
+ * %SKL_TKN_STR_LIB_NAME:       Specifies the library name
+ *
+ * module_id and loadable flags dont have tokens as these values will be
+ * read from the DSP FW manifest
+ */
+enum SKL_TKNS {
+	SKL_TKN_UUID = 1,
+	SKL_TKN_U8_NUM_BLOCKS,
+	SKL_TKN_U8_BLOCK_TYPE,
+	SKL_TKN_U8_IN_PIN_TYPE,
+	SKL_TKN_U8_OUT_PIN_TYPE,
+	SKL_TKN_U8_DYN_IN_PIN,
+	SKL_TKN_U8_DYN_OUT_PIN,
+	SKL_TKN_U8_IN_QUEUE_COUNT,
+	SKL_TKN_U8_OUT_QUEUE_COUNT,
+	SKL_TKN_U8_TIME_SLOT,
+	SKL_TKN_U8_CORE_ID,
+	SKL_TKN_U8_MOD_TYPE,
+	SKL_TKN_U8_CONN_TYPE,
+	SKL_TKN_U8_DEV_TYPE,
+	SKL_TKN_U8_HW_CONN_TYPE,
+	SKL_TKN_U16_MOD_INST_ID,
+	SKL_TKN_U16_BLOCK_SIZE,
+	SKL_TKN_U32_MAX_MCPS,
+	SKL_TKN_U32_MEM_PAGES,
+	SKL_TKN_U32_OBS,
+	SKL_TKN_U32_IBS,
+	SKL_TKN_U32_VBUS_ID,
+	SKL_TKN_U32_PARAMS_FIXUP,
+	SKL_TKN_U32_CONVERTER,
+	SKL_TKN_U32_PIPE_ID,
+	SKL_TKN_U32_PIPE_CONN_TYPE,
+	SKL_TKN_U32_PIPE_PRIORITY,
+	SKL_TKN_U32_PIPE_MEM_PGS,
+	SKL_TKN_U32_DIR_PIN_COUNT,
+	SKL_TKN_U32_FMT_CH,
+	SKL_TKN_U32_FMT_FREQ,
+	SKL_TKN_U32_FMT_BIT_DEPTH,
+	SKL_TKN_U32_FMT_SAMPLE_SIZE,
+	SKL_TKN_U32_FMT_CH_CONFIG,
+	SKL_TKN_U32_FMT_INTERLEAVE,
+	SKL_TKN_U32_FMT_SAMPLE_TYPE,
+	SKL_TKN_U32_FMT_CH_MAP,
+	SKL_TKN_U32_PIN_MOD_ID,
+	SKL_TKN_U32_PIN_INST_ID,
+	SKL_TKN_U32_MOD_SET_PARAMS,
+	SKL_TKN_U32_MOD_PARAM_ID,
+	SKL_TKN_U32_CAPS_SET_PARAMS,
+	SKL_TKN_U32_CAPS_PARAMS_ID,
+	SKL_TKN_U32_CAPS_SIZE,
+	SKL_TKN_U32_PROC_DOMAIN,
+	SKL_TKN_U32_LIB_COUNT,
+	SKL_TKN_STR_LIB_NAME,
+	SKL_TKN_MAX = SKL_TKN_STR_LIB_NAME,
+};
+
+#endif
diff --git a/include/uapi/sound/tlv.h b/include/uapi/sound/tlv.h
index ffc4f20..b4df440 100644
--- a/include/uapi/sound/tlv.h
+++ b/include/uapi/sound/tlv.h
@@ -28,4 +28,73 @@
 #define SNDRV_CTL_TLVT_CHMAP_VAR	0x102	/* channels freely swappable */
 #define SNDRV_CTL_TLVT_CHMAP_PAIRED	0x103	/* pair-wise swappable */
 
+/*
+ * TLV structure is right behind the struct snd_ctl_tlv:
+ *   unsigned int type  	- see SNDRV_CTL_TLVT_*
+ *   unsigned int length
+ *   .... data aligned to sizeof(unsigned int), use
+ *        block_length = (length + (sizeof(unsigned int) - 1)) &
+ *                       ~(sizeof(unsigned int) - 1)) ....
+ */
+#define SNDRV_CTL_TLVD_ITEM(type, ...) \
+	(type), SNDRV_CTL_TLVD_LENGTH(__VA_ARGS__), __VA_ARGS__
+#define SNDRV_CTL_TLVD_LENGTH(...) \
+	((unsigned int)sizeof((const unsigned int[]) { __VA_ARGS__ }))
+
+#define SNDRV_CTL_TLVD_CONTAINER_ITEM(...) \
+	SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_CONTAINER, __VA_ARGS__)
+#define SNDRV_CTL_TLVD_DECLARE_CONTAINER(name, ...) \
+	unsigned int name[] = { \
+		SNDRV_CTL_TLVD_CONTAINER_ITEM(__VA_ARGS__) \
+	}
+
+#define SNDRV_CTL_TLVD_DB_SCALE_MASK	0xffff
+#define SNDRV_CTL_TLVD_DB_SCALE_MUTE	0x10000
+#define SNDRV_CTL_TLVD_DB_SCALE_ITEM(min, step, mute) \
+	SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_SCALE, \
+			    (min), \
+			    ((step) & SNDRV_CTL_TLVD_DB_SCALE_MASK) | \
+			     ((mute) ? SNDRV_CTL_TLVD_DB_SCALE_MUTE : 0))
+#define SNDRV_CTL_TLVD_DECLARE_DB_SCALE(name, min, step, mute) \
+	unsigned int name[] = { \
+		SNDRV_CTL_TLVD_DB_SCALE_ITEM(min, step, mute) \
+	}
+
+/* dB scale specified with min/max values instead of step */
+#define SNDRV_CTL_TLVD_DB_MINMAX_ITEM(min_dB, max_dB) \
+	SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_MINMAX, (min_dB), (max_dB))
+#define SNDRV_CTL_TLVD_DB_MINMAX_MUTE_ITEM(min_dB, max_dB) \
+	SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_MINMAX_MUTE, (min_dB), (max_dB))
+#define SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(name, min_dB, max_dB) \
+	unsigned int name[] = { \
+		SNDRV_CTL_TLVD_DB_MINMAX_ITEM(min_dB, max_dB) \
+	}
+#define SNDRV_CTL_TLVD_DECLARE_DB_MINMAX_MUTE(name, min_dB, max_dB) \
+	unsigned int name[] = { \
+		SNDRV_CTL_TLVD_DB_MINMAX_MUTE_ITEM(min_dB, max_dB) \
+	}
+
+/* linear volume between min_dB and max_dB (.01dB unit) */
+#define SNDRV_CTL_TLVD_DB_LINEAR_ITEM(min_dB, max_dB) \
+	SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_LINEAR, (min_dB), (max_dB))
+#define SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(name, min_dB, max_dB) \
+	unsigned int name[] = { \
+		SNDRV_CTL_TLVD_DB_LINEAR_ITEM(min_dB, max_dB) \
+	}
+
+/* dB range container:
+ * Items in dB range container must be ordered by their values and by their
+ * dB values. This implies that larger values must correspond with larger
+ * dB values (which is also required for all other mixer controls).
+ */
+/* Each item is: <min> <max> <TLV> */
+#define SNDRV_CTL_TLVD_DB_RANGE_ITEM(...) \
+	SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_RANGE, __VA_ARGS__)
+#define SNDRV_CTL_TLVD_DECLARE_DB_RANGE(name, ...) \
+	unsigned int name[] = { \
+		SNDRV_CTL_TLVD_DB_RANGE_ITEM(__VA_ARGS__) \
+	}
+
+#define SNDRV_CTL_TLVD_DB_GAIN_MUTE	-9999999
+
 #endif
diff --git a/sound/aoa/fabrics/layout.c b/sound/aoa/fabrics/layout.c
index 8f71f7e..a0c4a5d 100644
--- a/sound/aoa/fabrics/layout.c
+++ b/sound/aoa/fabrics/layout.c
@@ -112,6 +112,7 @@
 
 MODULE_ALIAS("aoa-device-id-14");
 MODULE_ALIAS("aoa-device-id-22");
+MODULE_ALIAS("aoa-device-id-31");
 MODULE_ALIAS("aoa-device-id-35");
 MODULE_ALIAS("aoa-device-id-44");
 
@@ -362,6 +363,13 @@
 		.connections = tas_connections_nolineout,
 	  },
 	},
+	/* PowerBook6,1 */
+	{ .device_id = 31,
+	  .codecs[0] = {
+		.name = "tas",
+		.connections = tas_connections_nolineout,
+	  },
+	},
 	/* PowerBook6,5 */
 	{ .device_id = 44,
 	  .codecs[0] = {
@@ -1161,12 +1169,7 @@
 
 static int __init aoa_fabric_layout_init(void)
 {
-	int err;
-
-	err = soundbus_register_driver(&aoa_soundbus_driver);
-	if (err)
-		return err;
-	return 0;
+	return soundbus_register_driver(&aoa_soundbus_driver);
 }
 
 static void __exit aoa_fabric_layout_exit(void)
diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c
index 1cbf210..000b585 100644
--- a/sound/aoa/soundbus/i2sbus/core.c
+++ b/sound/aoa/soundbus/i2sbus/core.c
@@ -197,7 +197,7 @@
 			 * so restrict to those we do handle for now.
 			 */
 			if (id && (*id == 22 || *id == 14 || *id == 35 ||
-				   *id == 44)) {
+				   *id == 31 || *id == 44)) {
 				snprintf(dev->sound.modalias, 32,
 					 "aoa-device-id-%d", *id);
 				ok = 1;
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index 2c49848..fec1dfd 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -553,13 +553,9 @@
 		 * we should allow parameter change only when stream has been
 		 * opened not in other cases
 		 */
-		params = kmalloc(sizeof(*params), GFP_KERNEL);
-		if (!params)
-			return -ENOMEM;
-		if (copy_from_user(params, (void __user *)arg, sizeof(*params))) {
-			retval = -EFAULT;
-			goto out;
-		}
+		params = memdup_user((void __user *)arg, sizeof(*params));
+		if (IS_ERR(params))
+			return PTR_ERR(params);
 
 		retval = snd_compress_check_input(params);
 		if (retval)
@@ -784,7 +780,7 @@
 	ret = wait_event_interruptible(stream->runtime->sleep,
 			(stream->runtime->state != SNDRV_PCM_STATE_DRAINING));
 	if (ret == -ERESTARTSYS)
-		pr_debug("wait aborted by a signal");
+		pr_debug("wait aborted by a signal\n");
 	else if (ret)
 		pr_debug("wait for drain failed with %d\n", ret);
 
@@ -966,7 +962,7 @@
 				  compr->card, compr->device,
 				  &snd_compr_file_ops, compr, &compr->dev);
 	if (ret < 0) {
-		pr_err("snd_register_device failed\n %d", ret);
+		pr_err("snd_register_device failed %d\n", ret);
 		return ret;
 	}
 	return ret;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index c61fd50..9d33c1e 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -2637,9 +2637,11 @@
 			break;
 		/* Fall through */
 	case SNDRV_PCM_STATE_PREPARED:
-	case SNDRV_PCM_STATE_SUSPENDED:
 		err = 0;
 		break;
+	case SNDRV_PCM_STATE_SUSPENDED:
+		err = -ESTRPIPE;
+		break;
 	case SNDRV_PCM_STATE_XRUN:
 		err = -EPIPE;
 		break;
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index d6d9419..4c93520 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -87,21 +87,6 @@
 
 /*
  */
- 
-static inline mm_segment_t snd_enter_user(void)
-{
-	mm_segment_t fs = get_fs();
-	set_fs(get_ds());
-	return fs;
-}
-
-static inline void snd_leave_user(mm_segment_t fs)
-{
-	set_fs(fs);
-}
-
-/*
- */
 static inline unsigned short snd_seq_file_flags(struct file *file)
 {
         switch (file->f_mode & (FMODE_READ | FMODE_WRITE)) {
@@ -1128,59 +1113,69 @@
 
 /*-----------------------------------------------------*/
 
+static int snd_seq_ioctl_pversion(struct snd_seq_client *client, void *arg)
+{
+	int *pversion = arg;
+
+	*pversion = SNDRV_SEQ_VERSION;
+	return 0;
+}
+
+static int snd_seq_ioctl_client_id(struct snd_seq_client *client, void *arg)
+{
+	int *client_id = arg;
+
+	*client_id = client->number;
+	return 0;
+}
 
 /* SYSTEM_INFO ioctl() */
-static int snd_seq_ioctl_system_info(struct snd_seq_client *client, void __user *arg)
+static int snd_seq_ioctl_system_info(struct snd_seq_client *client, void *arg)
 {
-	struct snd_seq_system_info info;
+	struct snd_seq_system_info *info = arg;
 
-	memset(&info, 0, sizeof(info));
+	memset(info, 0, sizeof(*info));
 	/* fill the info fields */
-	info.queues = SNDRV_SEQ_MAX_QUEUES;
-	info.clients = SNDRV_SEQ_MAX_CLIENTS;
-	info.ports = SNDRV_SEQ_MAX_PORTS;
-	info.channels = 256;	/* fixed limit */
-	info.cur_clients = client_usage.cur;
-	info.cur_queues = snd_seq_queue_get_cur_queues();
+	info->queues = SNDRV_SEQ_MAX_QUEUES;
+	info->clients = SNDRV_SEQ_MAX_CLIENTS;
+	info->ports = SNDRV_SEQ_MAX_PORTS;
+	info->channels = 256;	/* fixed limit */
+	info->cur_clients = client_usage.cur;
+	info->cur_queues = snd_seq_queue_get_cur_queues();
 
-	if (copy_to_user(arg, &info, sizeof(info)))
-		return -EFAULT;
 	return 0;
 }
 
 
 /* RUNNING_MODE ioctl() */
-static int snd_seq_ioctl_running_mode(struct snd_seq_client *client, void __user *arg)
+static int snd_seq_ioctl_running_mode(struct snd_seq_client *client, void  *arg)
 {
-	struct snd_seq_running_info info;
+	struct snd_seq_running_info *info = arg;
 	struct snd_seq_client *cptr;
 	int err = 0;
 
-	if (copy_from_user(&info, arg, sizeof(info)))
-		return -EFAULT;
-
 	/* requested client number */
-	cptr = snd_seq_client_use_ptr(info.client);
+	cptr = snd_seq_client_use_ptr(info->client);
 	if (cptr == NULL)
 		return -ENOENT;		/* don't change !!! */
 
 #ifdef SNDRV_BIG_ENDIAN
-	if (! info.big_endian) {
+	if (!info->big_endian) {
 		err = -EINVAL;
 		goto __err;
 	}
 #else
-	if (info.big_endian) {
+	if (info->big_endian) {
 		err = -EINVAL;
 		goto __err;
 	}
 
 #endif
-	if (info.cpu_mode > sizeof(long)) {
+	if (info->cpu_mode > sizeof(long)) {
 		err = -EINVAL;
 		goto __err;
 	}
-	cptr->convert32 = (info.cpu_mode < sizeof(long));
+	cptr->convert32 = (info->cpu_mode < sizeof(long));
  __err:
 	snd_seq_client_unlock(cptr);
 	return err;
@@ -1214,51 +1209,43 @@
 }
 
 static int snd_seq_ioctl_get_client_info(struct snd_seq_client *client,
-					 void __user *arg)
+					 void *arg)
 {
+	struct snd_seq_client_info *client_info = arg;
 	struct snd_seq_client *cptr;
-	struct snd_seq_client_info client_info;
-
-	if (copy_from_user(&client_info, arg, sizeof(client_info)))
-		return -EFAULT;
 
 	/* requested client number */
-	cptr = snd_seq_client_use_ptr(client_info.client);
+	cptr = snd_seq_client_use_ptr(client_info->client);
 	if (cptr == NULL)
 		return -ENOENT;		/* don't change !!! */
 
-	get_client_info(cptr, &client_info);
+	get_client_info(cptr, client_info);
 	snd_seq_client_unlock(cptr);
 
-	if (copy_to_user(arg, &client_info, sizeof(client_info)))
-		return -EFAULT;
 	return 0;
 }
 
 
 /* CLIENT_INFO ioctl() */
 static int snd_seq_ioctl_set_client_info(struct snd_seq_client *client,
-					 void __user *arg)
+					 void *arg)
 {
-	struct snd_seq_client_info client_info;
-
-	if (copy_from_user(&client_info, arg, sizeof(client_info)))
-		return -EFAULT;
+	struct snd_seq_client_info *client_info = arg;
 
 	/* it is not allowed to set the info fields for an another client */
-	if (client->number != client_info.client)
+	if (client->number != client_info->client)
 		return -EPERM;
 	/* also client type must be set now */
-	if (client->type != client_info.type)
+	if (client->type != client_info->type)
 		return -EINVAL;
 
 	/* fill the info fields */
-	if (client_info.name[0])
-		strlcpy(client->name, client_info.name, sizeof(client->name));
+	if (client_info->name[0])
+		strlcpy(client->name, client_info->name, sizeof(client->name));
 
-	client->filter = client_info.filter;
-	client->event_lost = client_info.event_lost;
-	memcpy(client->event_filter, client_info.event_filter, 32);
+	client->filter = client_info->filter;
+	client->event_lost = client_info->event_lost;
+	memcpy(client->event_filter, client_info->event_filter, 32);
 
 	return 0;
 }
@@ -1267,30 +1254,26 @@
 /* 
  * CREATE PORT ioctl() 
  */
-static int snd_seq_ioctl_create_port(struct snd_seq_client *client,
-				     void __user *arg)
+static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg)
 {
+	struct snd_seq_port_info *info = arg;
 	struct snd_seq_client_port *port;
-	struct snd_seq_port_info info;
 	struct snd_seq_port_callback *callback;
 
-	if (copy_from_user(&info, arg, sizeof(info)))
-		return -EFAULT;
-
 	/* it is not allowed to create the port for an another client */
-	if (info.addr.client != client->number)
+	if (info->addr.client != client->number)
 		return -EPERM;
 
-	port = snd_seq_create_port(client, (info.flags & SNDRV_SEQ_PORT_FLG_GIVEN_PORT) ? info.addr.port : -1);
+	port = snd_seq_create_port(client, (info->flags & SNDRV_SEQ_PORT_FLG_GIVEN_PORT) ? info->addr.port : -1);
 	if (port == NULL)
 		return -ENOMEM;
 
-	if (client->type == USER_CLIENT && info.kernel) {
+	if (client->type == USER_CLIENT && info->kernel) {
 		snd_seq_delete_port(client, port->addr.port);
 		return -EINVAL;
 	}
 	if (client->type == KERNEL_CLIENT) {
-		if ((callback = info.kernel) != NULL) {
+		if ((callback = info->kernel) != NULL) {
 			if (callback->owner)
 				port->owner = callback->owner;
 			port->private_data = callback->private_data;
@@ -1303,37 +1286,29 @@
 		}
 	}
 
-	info.addr = port->addr;
+	info->addr = port->addr;
 
-	snd_seq_set_port_info(port, &info);
+	snd_seq_set_port_info(port, info);
 	snd_seq_system_client_ev_port_start(port->addr.client, port->addr.port);
 
-	if (copy_to_user(arg, &info, sizeof(info)))
-		return -EFAULT;
-
 	return 0;
 }
 
 /* 
  * DELETE PORT ioctl() 
  */
-static int snd_seq_ioctl_delete_port(struct snd_seq_client *client,
-				     void __user *arg)
+static int snd_seq_ioctl_delete_port(struct snd_seq_client *client, void *arg)
 {
-	struct snd_seq_port_info info;
+	struct snd_seq_port_info *info = arg;
 	int err;
 
-	/* set passed parameters */
-	if (copy_from_user(&info, arg, sizeof(info)))
-		return -EFAULT;
-	
 	/* it is not allowed to remove the port for an another client */
-	if (info.addr.client != client->number)
+	if (info->addr.client != client->number)
 		return -EPERM;
 
-	err = snd_seq_delete_port(client, info.addr.port);
+	err = snd_seq_delete_port(client, info->addr.port);
 	if (err >= 0)
-		snd_seq_system_client_ev_port_exit(client->number, info.addr.port);
+		snd_seq_system_client_ev_port_exit(client->number, info->addr.port);
 	return err;
 }
 
@@ -1341,32 +1316,27 @@
 /* 
  * GET_PORT_INFO ioctl() (on any client) 
  */
-static int snd_seq_ioctl_get_port_info(struct snd_seq_client *client,
-				       void __user *arg)
+static int snd_seq_ioctl_get_port_info(struct snd_seq_client *client, void *arg)
 {
+	struct snd_seq_port_info *info = arg;
 	struct snd_seq_client *cptr;
 	struct snd_seq_client_port *port;
-	struct snd_seq_port_info info;
 
-	if (copy_from_user(&info, arg, sizeof(info)))
-		return -EFAULT;
-	cptr = snd_seq_client_use_ptr(info.addr.client);
+	cptr = snd_seq_client_use_ptr(info->addr.client);
 	if (cptr == NULL)
 		return -ENXIO;
 
-	port = snd_seq_port_use_ptr(cptr, info.addr.port);
+	port = snd_seq_port_use_ptr(cptr, info->addr.port);
 	if (port == NULL) {
 		snd_seq_client_unlock(cptr);
 		return -ENOENT;			/* don't change */
 	}
 
 	/* get port info */
-	snd_seq_get_port_info(port, &info);
+	snd_seq_get_port_info(port, info);
 	snd_seq_port_unlock(port);
 	snd_seq_client_unlock(cptr);
 
-	if (copy_to_user(arg, &info, sizeof(info)))
-		return -EFAULT;
 	return 0;
 }
 
@@ -1374,20 +1344,16 @@
 /* 
  * SET_PORT_INFO ioctl() (only ports on this/own client) 
  */
-static int snd_seq_ioctl_set_port_info(struct snd_seq_client *client,
-				       void __user *arg)
+static int snd_seq_ioctl_set_port_info(struct snd_seq_client *client, void *arg)
 {
+	struct snd_seq_port_info *info = arg;
 	struct snd_seq_client_port *port;
-	struct snd_seq_port_info info;
 
-	if (copy_from_user(&info, arg, sizeof(info)))
-		return -EFAULT;
-
-	if (info.addr.client != client->number) /* only set our own ports ! */
+	if (info->addr.client != client->number) /* only set our own ports ! */
 		return -EPERM;
-	port = snd_seq_port_use_ptr(client, info.addr.port);
+	port = snd_seq_port_use_ptr(client, info->addr.port);
 	if (port) {
-		snd_seq_set_port_info(port, &info);
+		snd_seq_set_port_info(port, info);
 		snd_seq_port_unlock(port);
 	}
 	return 0;
@@ -1453,34 +1419,31 @@
  * add to port's subscription list IOCTL interface 
  */
 static int snd_seq_ioctl_subscribe_port(struct snd_seq_client *client,
-					void __user *arg)
+					void *arg)
 {
+	struct snd_seq_port_subscribe *subs = arg;
 	int result = -EINVAL;
 	struct snd_seq_client *receiver = NULL, *sender = NULL;
 	struct snd_seq_client_port *sport = NULL, *dport = NULL;
-	struct snd_seq_port_subscribe subs;
 
-	if (copy_from_user(&subs, arg, sizeof(subs)))
-		return -EFAULT;
-
-	if ((receiver = snd_seq_client_use_ptr(subs.dest.client)) == NULL)
+	if ((receiver = snd_seq_client_use_ptr(subs->dest.client)) == NULL)
 		goto __end;
-	if ((sender = snd_seq_client_use_ptr(subs.sender.client)) == NULL)
+	if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL)
 		goto __end;
-	if ((sport = snd_seq_port_use_ptr(sender, subs.sender.port)) == NULL)
+	if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL)
 		goto __end;
-	if ((dport = snd_seq_port_use_ptr(receiver, subs.dest.port)) == NULL)
+	if ((dport = snd_seq_port_use_ptr(receiver, subs->dest.port)) == NULL)
 		goto __end;
 
-	result = check_subscription_permission(client, sport, dport, &subs);
+	result = check_subscription_permission(client, sport, dport, subs);
 	if (result < 0)
 		goto __end;
 
 	/* connect them */
-	result = snd_seq_port_connect(client, sender, sport, receiver, dport, &subs);
+	result = snd_seq_port_connect(client, sender, sport, receiver, dport, subs);
 	if (! result) /* broadcast announce */
 		snd_seq_client_notify_subscription(SNDRV_SEQ_ADDRESS_SUBSCRIBERS, 0,
-						   &subs, SNDRV_SEQ_EVENT_PORT_SUBSCRIBED);
+						   subs, SNDRV_SEQ_EVENT_PORT_SUBSCRIBED);
       __end:
       	if (sport)
 		snd_seq_port_unlock(sport);
@@ -1498,33 +1461,30 @@
  * remove from port's subscription list 
  */
 static int snd_seq_ioctl_unsubscribe_port(struct snd_seq_client *client,
-					  void __user *arg)
+					  void *arg)
 {
+	struct snd_seq_port_subscribe *subs = arg;
 	int result = -ENXIO;
 	struct snd_seq_client *receiver = NULL, *sender = NULL;
 	struct snd_seq_client_port *sport = NULL, *dport = NULL;
-	struct snd_seq_port_subscribe subs;
 
-	if (copy_from_user(&subs, arg, sizeof(subs)))
-		return -EFAULT;
-
-	if ((receiver = snd_seq_client_use_ptr(subs.dest.client)) == NULL)
+	if ((receiver = snd_seq_client_use_ptr(subs->dest.client)) == NULL)
 		goto __end;
-	if ((sender = snd_seq_client_use_ptr(subs.sender.client)) == NULL)
+	if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL)
 		goto __end;
-	if ((sport = snd_seq_port_use_ptr(sender, subs.sender.port)) == NULL)
+	if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL)
 		goto __end;
-	if ((dport = snd_seq_port_use_ptr(receiver, subs.dest.port)) == NULL)
+	if ((dport = snd_seq_port_use_ptr(receiver, subs->dest.port)) == NULL)
 		goto __end;
 
-	result = check_subscription_permission(client, sport, dport, &subs);
+	result = check_subscription_permission(client, sport, dport, subs);
 	if (result < 0)
 		goto __end;
 
-	result = snd_seq_port_disconnect(client, sender, sport, receiver, dport, &subs);
+	result = snd_seq_port_disconnect(client, sender, sport, receiver, dport, subs);
 	if (! result) /* broadcast announce */
 		snd_seq_client_notify_subscription(SNDRV_SEQ_ADDRESS_SUBSCRIBERS, 0,
-						   &subs, SNDRV_SEQ_EVENT_PORT_UNSUBSCRIBED);
+						   subs, SNDRV_SEQ_EVENT_PORT_UNSUBSCRIBED);
       __end:
       	if (sport)
 		snd_seq_port_unlock(sport);
@@ -1539,17 +1499,13 @@
 
 
 /* CREATE_QUEUE ioctl() */
-static int snd_seq_ioctl_create_queue(struct snd_seq_client *client,
-				      void __user *arg)
+static int snd_seq_ioctl_create_queue(struct snd_seq_client *client, void *arg)
 {
-	struct snd_seq_queue_info info;
+	struct snd_seq_queue_info *info = arg;
 	int result;
 	struct snd_seq_queue *q;
 
-	if (copy_from_user(&info, arg, sizeof(info)))
-		return -EFAULT;
-
-	result = snd_seq_queue_alloc(client->number, info.locked, info.flags);
+	result = snd_seq_queue_alloc(client->number, info->locked, info->flags);
 	if (result < 0)
 		return result;
 
@@ -1557,181 +1513,150 @@
 	if (q == NULL)
 		return -EINVAL;
 
-	info.queue = q->queue;
-	info.locked = q->locked;
-	info.owner = q->owner;
+	info->queue = q->queue;
+	info->locked = q->locked;
+	info->owner = q->owner;
 
 	/* set queue name */
-	if (! info.name[0])
-		snprintf(info.name, sizeof(info.name), "Queue-%d", q->queue);
-	strlcpy(q->name, info.name, sizeof(q->name));
+	if (!info->name[0])
+		snprintf(info->name, sizeof(info->name), "Queue-%d", q->queue);
+	strlcpy(q->name, info->name, sizeof(q->name));
 	queuefree(q);
 
-	if (copy_to_user(arg, &info, sizeof(info)))
-		return -EFAULT;
-
 	return 0;
 }
 
 /* DELETE_QUEUE ioctl() */
-static int snd_seq_ioctl_delete_queue(struct snd_seq_client *client,
-				      void __user *arg)
+static int snd_seq_ioctl_delete_queue(struct snd_seq_client *client, void *arg)
 {
-	struct snd_seq_queue_info info;
+	struct snd_seq_queue_info *info = arg;
 
-	if (copy_from_user(&info, arg, sizeof(info)))
-		return -EFAULT;
-
-	return snd_seq_queue_delete(client->number, info.queue);
+	return snd_seq_queue_delete(client->number, info->queue);
 }
 
 /* GET_QUEUE_INFO ioctl() */
 static int snd_seq_ioctl_get_queue_info(struct snd_seq_client *client,
-					void __user *arg)
+					void *arg)
 {
-	struct snd_seq_queue_info info;
+	struct snd_seq_queue_info *info = arg;
 	struct snd_seq_queue *q;
 
-	if (copy_from_user(&info, arg, sizeof(info)))
-		return -EFAULT;
-
-	q = queueptr(info.queue);
+	q = queueptr(info->queue);
 	if (q == NULL)
 		return -EINVAL;
 
-	memset(&info, 0, sizeof(info));
-	info.queue = q->queue;
-	info.owner = q->owner;
-	info.locked = q->locked;
-	strlcpy(info.name, q->name, sizeof(info.name));
+	memset(info, 0, sizeof(*info));
+	info->queue = q->queue;
+	info->owner = q->owner;
+	info->locked = q->locked;
+	strlcpy(info->name, q->name, sizeof(info->name));
 	queuefree(q);
 
-	if (copy_to_user(arg, &info, sizeof(info)))
-		return -EFAULT;
-
 	return 0;
 }
 
 /* SET_QUEUE_INFO ioctl() */
 static int snd_seq_ioctl_set_queue_info(struct snd_seq_client *client,
-					void __user *arg)
+					void *arg)
 {
-	struct snd_seq_queue_info info;
+	struct snd_seq_queue_info *info = arg;
 	struct snd_seq_queue *q;
 
-	if (copy_from_user(&info, arg, sizeof(info)))
-		return -EFAULT;
-
-	if (info.owner != client->number)
+	if (info->owner != client->number)
 		return -EINVAL;
 
 	/* change owner/locked permission */
-	if (snd_seq_queue_check_access(info.queue, client->number)) {
-		if (snd_seq_queue_set_owner(info.queue, client->number, info.locked) < 0)
+	if (snd_seq_queue_check_access(info->queue, client->number)) {
+		if (snd_seq_queue_set_owner(info->queue, client->number, info->locked) < 0)
 			return -EPERM;
-		if (info.locked)
-			snd_seq_queue_use(info.queue, client->number, 1);
+		if (info->locked)
+			snd_seq_queue_use(info->queue, client->number, 1);
 	} else {
 		return -EPERM;
 	}	
 
-	q = queueptr(info.queue);
+	q = queueptr(info->queue);
 	if (! q)
 		return -EINVAL;
 	if (q->owner != client->number) {
 		queuefree(q);
 		return -EPERM;
 	}
-	strlcpy(q->name, info.name, sizeof(q->name));
+	strlcpy(q->name, info->name, sizeof(q->name));
 	queuefree(q);
 
 	return 0;
 }
 
 /* GET_NAMED_QUEUE ioctl() */
-static int snd_seq_ioctl_get_named_queue(struct snd_seq_client *client, void __user *arg)
+static int snd_seq_ioctl_get_named_queue(struct snd_seq_client *client,
+					 void *arg)
 {
-	struct snd_seq_queue_info info;
+	struct snd_seq_queue_info *info = arg;
 	struct snd_seq_queue *q;
 
-	if (copy_from_user(&info, arg, sizeof(info)))
-		return -EFAULT;
-
-	q = snd_seq_queue_find_name(info.name);
+	q = snd_seq_queue_find_name(info->name);
 	if (q == NULL)
 		return -EINVAL;
-	info.queue = q->queue;
-	info.owner = q->owner;
-	info.locked = q->locked;
+	info->queue = q->queue;
+	info->owner = q->owner;
+	info->locked = q->locked;
 	queuefree(q);
 
-	if (copy_to_user(arg, &info, sizeof(info)))
-		return -EFAULT;
-
 	return 0;
 }
 
 /* GET_QUEUE_STATUS ioctl() */
 static int snd_seq_ioctl_get_queue_status(struct snd_seq_client *client,
-					  void __user *arg)
+					  void *arg)
 {
-	struct snd_seq_queue_status status;
+	struct snd_seq_queue_status *status = arg;
 	struct snd_seq_queue *queue;
 	struct snd_seq_timer *tmr;
 
-	if (copy_from_user(&status, arg, sizeof(status)))
-		return -EFAULT;
-
-	queue = queueptr(status.queue);
+	queue = queueptr(status->queue);
 	if (queue == NULL)
 		return -EINVAL;
-	memset(&status, 0, sizeof(status));
-	status.queue = queue->queue;
+	memset(status, 0, sizeof(*status));
+	status->queue = queue->queue;
 	
 	tmr = queue->timer;
-	status.events = queue->tickq->cells + queue->timeq->cells;
+	status->events = queue->tickq->cells + queue->timeq->cells;
 
-	status.time = snd_seq_timer_get_cur_time(tmr);
-	status.tick = snd_seq_timer_get_cur_tick(tmr);
+	status->time = snd_seq_timer_get_cur_time(tmr);
+	status->tick = snd_seq_timer_get_cur_tick(tmr);
 
-	status.running = tmr->running;
+	status->running = tmr->running;
 
-	status.flags = queue->flags;
+	status->flags = queue->flags;
 	queuefree(queue);
 
-	if (copy_to_user(arg, &status, sizeof(status)))
-		return -EFAULT;
 	return 0;
 }
 
 
 /* GET_QUEUE_TEMPO ioctl() */
 static int snd_seq_ioctl_get_queue_tempo(struct snd_seq_client *client,
-					 void __user *arg)
+					 void *arg)
 {
-	struct snd_seq_queue_tempo tempo;
+	struct snd_seq_queue_tempo *tempo = arg;
 	struct snd_seq_queue *queue;
 	struct snd_seq_timer *tmr;
 
-	if (copy_from_user(&tempo, arg, sizeof(tempo)))
-		return -EFAULT;
-
-	queue = queueptr(tempo.queue);
+	queue = queueptr(tempo->queue);
 	if (queue == NULL)
 		return -EINVAL;
-	memset(&tempo, 0, sizeof(tempo));
-	tempo.queue = queue->queue;
+	memset(tempo, 0, sizeof(*tempo));
+	tempo->queue = queue->queue;
 	
 	tmr = queue->timer;
 
-	tempo.tempo = tmr->tempo;
-	tempo.ppq = tmr->ppq;
-	tempo.skew_value = tmr->skew;
-	tempo.skew_base = tmr->skew_base;
+	tempo->tempo = tmr->tempo;
+	tempo->ppq = tmr->ppq;
+	tempo->skew_value = tmr->skew;
+	tempo->skew_base = tmr->skew_base;
 	queuefree(queue);
 
-	if (copy_to_user(arg, &tempo, sizeof(tempo)))
-		return -EFAULT;
 	return 0;
 }
 
@@ -1747,31 +1672,25 @@
 EXPORT_SYMBOL(snd_seq_set_queue_tempo);
 
 static int snd_seq_ioctl_set_queue_tempo(struct snd_seq_client *client,
-					 void __user *arg)
+					 void *arg)
 {
+	struct snd_seq_queue_tempo *tempo = arg;
 	int result;
-	struct snd_seq_queue_tempo tempo;
 
-	if (copy_from_user(&tempo, arg, sizeof(tempo)))
-		return -EFAULT;
-
-	result = snd_seq_set_queue_tempo(client->number, &tempo);
+	result = snd_seq_set_queue_tempo(client->number, tempo);
 	return result < 0 ? result : 0;
 }
 
 
 /* GET_QUEUE_TIMER ioctl() */
 static int snd_seq_ioctl_get_queue_timer(struct snd_seq_client *client,
-					 void __user *arg)
+					 void *arg)
 {
-	struct snd_seq_queue_timer timer;
+	struct snd_seq_queue_timer *timer = arg;
 	struct snd_seq_queue *queue;
 	struct snd_seq_timer *tmr;
 
-	if (copy_from_user(&timer, arg, sizeof(timer)))
-		return -EFAULT;
-
-	queue = queueptr(timer.queue);
+	queue = queueptr(timer->queue);
 	if (queue == NULL)
 		return -EINVAL;
 
@@ -1780,41 +1699,36 @@
 		return -ERESTARTSYS;
 	}
 	tmr = queue->timer;
-	memset(&timer, 0, sizeof(timer));
-	timer.queue = queue->queue;
+	memset(timer, 0, sizeof(*timer));
+	timer->queue = queue->queue;
 
-	timer.type = tmr->type;
+	timer->type = tmr->type;
 	if (tmr->type == SNDRV_SEQ_TIMER_ALSA) {
-		timer.u.alsa.id = tmr->alsa_id;
-		timer.u.alsa.resolution = tmr->preferred_resolution;
+		timer->u.alsa.id = tmr->alsa_id;
+		timer->u.alsa.resolution = tmr->preferred_resolution;
 	}
 	mutex_unlock(&queue->timer_mutex);
 	queuefree(queue);
 	
-	if (copy_to_user(arg, &timer, sizeof(timer)))
-		return -EFAULT;
 	return 0;
 }
 
 
 /* SET_QUEUE_TIMER ioctl() */
 static int snd_seq_ioctl_set_queue_timer(struct snd_seq_client *client,
-					 void __user *arg)
+					 void *arg)
 {
+	struct snd_seq_queue_timer *timer = arg;
 	int result = 0;
-	struct snd_seq_queue_timer timer;
 
-	if (copy_from_user(&timer, arg, sizeof(timer)))
-		return -EFAULT;
-
-	if (timer.type != SNDRV_SEQ_TIMER_ALSA)
+	if (timer->type != SNDRV_SEQ_TIMER_ALSA)
 		return -EINVAL;
 
-	if (snd_seq_queue_check_access(timer.queue, client->number)) {
+	if (snd_seq_queue_check_access(timer->queue, client->number)) {
 		struct snd_seq_queue *q;
 		struct snd_seq_timer *tmr;
 
-		q = queueptr(timer.queue);
+		q = queueptr(timer->queue);
 		if (q == NULL)
 			return -ENXIO;
 		if (mutex_lock_interruptible(&q->timer_mutex)) {
@@ -1822,13 +1736,13 @@
 			return -ERESTARTSYS;
 		}
 		tmr = q->timer;
-		snd_seq_queue_timer_close(timer.queue);
-		tmr->type = timer.type;
+		snd_seq_queue_timer_close(timer->queue);
+		tmr->type = timer->type;
 		if (tmr->type == SNDRV_SEQ_TIMER_ALSA) {
-			tmr->alsa_id = timer.u.alsa.id;
-			tmr->preferred_resolution = timer.u.alsa.resolution;
+			tmr->alsa_id = timer->u.alsa.id;
+			tmr->preferred_resolution = timer->u.alsa.resolution;
 		}
-		result = snd_seq_queue_timer_open(timer.queue);
+		result = snd_seq_queue_timer_open(timer->queue);
 		mutex_unlock(&q->timer_mutex);
 		queuefree(q);
 	} else {
@@ -1841,38 +1755,30 @@
 
 /* GET_QUEUE_CLIENT ioctl() */
 static int snd_seq_ioctl_get_queue_client(struct snd_seq_client *client,
-					  void __user *arg)
+					  void *arg)
 {
-	struct snd_seq_queue_client info;
+	struct snd_seq_queue_client *info = arg;
 	int used;
 
-	if (copy_from_user(&info, arg, sizeof(info)))
-		return -EFAULT;
-
-	used = snd_seq_queue_is_used(info.queue, client->number);
+	used = snd_seq_queue_is_used(info->queue, client->number);
 	if (used < 0)
 		return -EINVAL;
-	info.used = used;
-	info.client = client->number;
+	info->used = used;
+	info->client = client->number;
 
-	if (copy_to_user(arg, &info, sizeof(info)))
-		return -EFAULT;
 	return 0;
 }
 
 
 /* SET_QUEUE_CLIENT ioctl() */
 static int snd_seq_ioctl_set_queue_client(struct snd_seq_client *client,
-					  void __user *arg)
+					  void *arg)
 {
+	struct snd_seq_queue_client *info = arg;
 	int err;
-	struct snd_seq_queue_client info;
 
-	if (copy_from_user(&info, arg, sizeof(info)))
-		return -EFAULT;
-
-	if (info.used >= 0) {
-		err = snd_seq_queue_use(info.queue, client->number, info.used);
+	if (info->used >= 0) {
+		err = snd_seq_queue_use(info->queue, client->number, info->used);
 		if (err < 0)
 			return err;
 	}
@@ -1883,78 +1789,70 @@
 
 /* GET_CLIENT_POOL ioctl() */
 static int snd_seq_ioctl_get_client_pool(struct snd_seq_client *client,
-					 void __user *arg)
+					 void *arg)
 {
-	struct snd_seq_client_pool info;
+	struct snd_seq_client_pool *info = arg;
 	struct snd_seq_client *cptr;
 
-	if (copy_from_user(&info, arg, sizeof(info)))
-		return -EFAULT;
-
-	cptr = snd_seq_client_use_ptr(info.client);
+	cptr = snd_seq_client_use_ptr(info->client);
 	if (cptr == NULL)
 		return -ENOENT;
-	memset(&info, 0, sizeof(info));
-	info.client = cptr->number;
-	info.output_pool = cptr->pool->size;
-	info.output_room = cptr->pool->room;
-	info.output_free = info.output_pool;
-	info.output_free = snd_seq_unused_cells(cptr->pool);
+	memset(info, 0, sizeof(*info));
+	info->client = cptr->number;
+	info->output_pool = cptr->pool->size;
+	info->output_room = cptr->pool->room;
+	info->output_free = info->output_pool;
+	info->output_free = snd_seq_unused_cells(cptr->pool);
 	if (cptr->type == USER_CLIENT) {
-		info.input_pool = cptr->data.user.fifo_pool_size;
-		info.input_free = info.input_pool;
+		info->input_pool = cptr->data.user.fifo_pool_size;
+		info->input_free = info->input_pool;
 		if (cptr->data.user.fifo)
-			info.input_free = snd_seq_unused_cells(cptr->data.user.fifo->pool);
+			info->input_free = snd_seq_unused_cells(cptr->data.user.fifo->pool);
 	} else {
-		info.input_pool = 0;
-		info.input_free = 0;
+		info->input_pool = 0;
+		info->input_free = 0;
 	}
 	snd_seq_client_unlock(cptr);
 	
-	if (copy_to_user(arg, &info, sizeof(info)))
-		return -EFAULT;
 	return 0;
 }
 
 /* SET_CLIENT_POOL ioctl() */
 static int snd_seq_ioctl_set_client_pool(struct snd_seq_client *client,
-					 void __user *arg)
+					 void *arg)
 {
-	struct snd_seq_client_pool info;
+	struct snd_seq_client_pool *info = arg;
 	int rc;
 
-	if (copy_from_user(&info, arg, sizeof(info)))
-		return -EFAULT;
-
-	if (client->number != info.client)
+	if (client->number != info->client)
 		return -EINVAL; /* can't change other clients */
 
-	if (info.output_pool >= 1 && info.output_pool <= SNDRV_SEQ_MAX_EVENTS &&
+	if (info->output_pool >= 1 && info->output_pool <= SNDRV_SEQ_MAX_EVENTS &&
 	    (! snd_seq_write_pool_allocated(client) ||
-	     info.output_pool != client->pool->size)) {
+	     info->output_pool != client->pool->size)) {
 		if (snd_seq_write_pool_allocated(client)) {
 			/* remove all existing cells */
 			snd_seq_queue_client_leave_cells(client->number);
 			snd_seq_pool_done(client->pool);
 		}
-		client->pool->size = info.output_pool;
+		client->pool->size = info->output_pool;
 		rc = snd_seq_pool_init(client->pool);
 		if (rc < 0)
 			return rc;
 	}
 	if (client->type == USER_CLIENT && client->data.user.fifo != NULL &&
-	    info.input_pool >= 1 &&
-	    info.input_pool <= SNDRV_SEQ_MAX_CLIENT_EVENTS &&
-	    info.input_pool != client->data.user.fifo_pool_size) {
+	    info->input_pool >= 1 &&
+	    info->input_pool <= SNDRV_SEQ_MAX_CLIENT_EVENTS &&
+	    info->input_pool != client->data.user.fifo_pool_size) {
 		/* change pool size */
-		rc = snd_seq_fifo_resize(client->data.user.fifo, info.input_pool);
+		rc = snd_seq_fifo_resize(client->data.user.fifo, info->input_pool);
 		if (rc < 0)
 			return rc;
-		client->data.user.fifo_pool_size = info.input_pool;
+		client->data.user.fifo_pool_size = info->input_pool;
 	}
-	if (info.output_room >= 1 &&
-	    info.output_room <= client->pool->size) {
-		client->pool->room  = info.output_room;
+	if (info->output_room >= 1 &&
+	    info->output_room <= client->pool->size) {
+		client->pool->room  = info->output_room;
 	}
 
 	return snd_seq_ioctl_get_client_pool(client, arg);
@@ -1963,17 +1861,14 @@
 
 /* REMOVE_EVENTS ioctl() */
 static int snd_seq_ioctl_remove_events(struct snd_seq_client *client,
-				       void __user *arg)
+				       void *arg)
 {
-	struct snd_seq_remove_events info;
-
-	if (copy_from_user(&info, arg, sizeof(info)))
-		return -EFAULT;
+	struct snd_seq_remove_events *info = arg;
 
 	/*
 	 * Input mostly not implemented XXX.
 	 */
-	if (info.remove_mode & SNDRV_SEQ_REMOVE_INPUT) {
+	if (info->remove_mode & SNDRV_SEQ_REMOVE_INPUT) {
 		/*
 		 * No restrictions so for a user client we can clear
 		 * the whole fifo
@@ -1982,8 +1877,8 @@
 			snd_seq_fifo_clear(client->data.user.fifo);
 	}
 
-	if (info.remove_mode & SNDRV_SEQ_REMOVE_OUTPUT)
-		snd_seq_queue_remove_cells(client->number, &info);
+	if (info->remove_mode & SNDRV_SEQ_REMOVE_OUTPUT)
+		snd_seq_queue_remove_cells(client->number, info);
 
 	return 0;
 }
@@ -1993,26 +1888,23 @@
  * get subscription info
  */
 static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client,
-					  void __user *arg)
+					  void *arg)
 {
+	struct snd_seq_port_subscribe *subs = arg;
 	int result;
 	struct snd_seq_client *sender = NULL;
 	struct snd_seq_client_port *sport = NULL;
-	struct snd_seq_port_subscribe subs;
 	struct snd_seq_subscribers *p;
 
-	if (copy_from_user(&subs, arg, sizeof(subs)))
-		return -EFAULT;
-
 	result = -EINVAL;
-	if ((sender = snd_seq_client_use_ptr(subs.sender.client)) == NULL)
+	if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL)
 		goto __end;
-	if ((sport = snd_seq_port_use_ptr(sender, subs.sender.port)) == NULL)
+	if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL)
 		goto __end;
-	p = snd_seq_port_get_subscription(&sport->c_src, &subs.dest);
+	p = snd_seq_port_get_subscription(&sport->c_src, &subs->dest);
 	if (p) {
 		result = 0;
-		subs = p->info;
+		*subs = p->info;
 	} else
 		result = -ENOENT;
 
@@ -2021,10 +1913,7 @@
 		snd_seq_port_unlock(sport);
 	if (sender)
 		snd_seq_client_unlock(sender);
-	if (result >= 0) {
-		if (copy_to_user(arg, &subs, sizeof(subs)))
-			return -EFAULT;
-	}
+
 	return result;
 }
 
@@ -2032,26 +1921,22 @@
 /*
  * get subscription info - check only its presence
  */
-static int snd_seq_ioctl_query_subs(struct snd_seq_client *client,
-				    void __user *arg)
+static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg)
 {
+	struct snd_seq_query_subs *subs = arg;
 	int result = -ENXIO;
 	struct snd_seq_client *cptr = NULL;
 	struct snd_seq_client_port *port = NULL;
-	struct snd_seq_query_subs subs;
 	struct snd_seq_port_subs_info *group;
 	struct list_head *p;
 	int i;
 
-	if (copy_from_user(&subs, arg, sizeof(subs)))
-		return -EFAULT;
-
-	if ((cptr = snd_seq_client_use_ptr(subs.root.client)) == NULL)
+	if ((cptr = snd_seq_client_use_ptr(subs->root.client)) == NULL)
 		goto __end;
-	if ((port = snd_seq_port_use_ptr(cptr, subs.root.port)) == NULL)
+	if ((port = snd_seq_port_use_ptr(cptr, subs->root.port)) == NULL)
 		goto __end;
 
-	switch (subs.type) {
+	switch (subs->type) {
 	case SNDRV_SEQ_QUERY_SUBS_READ:
 		group = &port->c_src;
 		break;
@@ -2064,22 +1949,22 @@
 
 	down_read(&group->list_mutex);
 	/* search for the subscriber */
-	subs.num_subs = group->count;
+	subs->num_subs = group->count;
 	i = 0;
 	result = -ENOENT;
 	list_for_each(p, &group->list_head) {
-		if (i++ == subs.index) {
+		if (i++ == subs->index) {
 			/* found! */
 			struct snd_seq_subscribers *s;
-			if (subs.type == SNDRV_SEQ_QUERY_SUBS_READ) {
+			if (subs->type == SNDRV_SEQ_QUERY_SUBS_READ) {
 				s = list_entry(p, struct snd_seq_subscribers, src_list);
-				subs.addr = s->info.dest;
+				subs->addr = s->info.dest;
 			} else {
 				s = list_entry(p, struct snd_seq_subscribers, dest_list);
-				subs.addr = s->info.sender;
+				subs->addr = s->info.sender;
 			}
-			subs.flags = s->info.flags;
-			subs.queue = s->info.queue;
+			subs->flags = s->info.flags;
+			subs->queue = s->info.queue;
 			result = 0;
 			break;
 		}
@@ -2091,10 +1976,7 @@
 		snd_seq_port_unlock(port);
 	if (cptr)
 		snd_seq_client_unlock(cptr);
-	if (result >= 0) {
-		if (copy_to_user(arg, &subs, sizeof(subs)))
-			return -EFAULT;
-	}
+
 	return result;
 }
 
@@ -2103,31 +1985,26 @@
  * query next client
  */
 static int snd_seq_ioctl_query_next_client(struct snd_seq_client *client,
-					   void __user *arg)
+					   void *arg)
 {
+	struct snd_seq_client_info *info = arg;
 	struct snd_seq_client *cptr = NULL;
-	struct snd_seq_client_info info;
-
-	if (copy_from_user(&info, arg, sizeof(info)))
-		return -EFAULT;
 
 	/* search for next client */
-	info.client++;
-	if (info.client < 0)
-		info.client = 0;
-	for (; info.client < SNDRV_SEQ_MAX_CLIENTS; info.client++) {
-		cptr = snd_seq_client_use_ptr(info.client);
+	info->client++;
+	if (info->client < 0)
+		info->client = 0;
+	for (; info->client < SNDRV_SEQ_MAX_CLIENTS; info->client++) {
+		cptr = snd_seq_client_use_ptr(info->client);
 		if (cptr)
 			break; /* found */
 	}
 	if (cptr == NULL)
 		return -ENOENT;
 
-	get_client_info(cptr, &info);
+	get_client_info(cptr, info);
 	snd_seq_client_unlock(cptr);
 
-	if (copy_to_user(arg, &info, sizeof(info)))
-		return -EFAULT;
 	return 0;
 }
 
@@ -2135,43 +2012,41 @@
  * query next port
  */
 static int snd_seq_ioctl_query_next_port(struct snd_seq_client *client,
-					 void __user *arg)
+					 void *arg)
 {
+	struct snd_seq_port_info *info = arg;
 	struct snd_seq_client *cptr;
 	struct snd_seq_client_port *port = NULL;
-	struct snd_seq_port_info info;
 
-	if (copy_from_user(&info, arg, sizeof(info)))
-		return -EFAULT;
-	cptr = snd_seq_client_use_ptr(info.addr.client);
+	cptr = snd_seq_client_use_ptr(info->addr.client);
 	if (cptr == NULL)
 		return -ENXIO;
 
 	/* search for next port */
-	info.addr.port++;
-	port = snd_seq_port_query_nearest(cptr, &info);
+	info->addr.port++;
+	port = snd_seq_port_query_nearest(cptr, info);
 	if (port == NULL) {
 		snd_seq_client_unlock(cptr);
 		return -ENOENT;
 	}
 
 	/* get port info */
-	info.addr = port->addr;
-	snd_seq_get_port_info(port, &info);
+	info->addr = port->addr;
+	snd_seq_get_port_info(port, info);
 	snd_seq_port_unlock(port);
 	snd_seq_client_unlock(cptr);
 
-	if (copy_to_user(arg, &info, sizeof(info)))
-		return -EFAULT;
 	return 0;
 }
 
 /* -------------------------------------------------------- */
 
-static struct seq_ioctl_table {
+static const struct ioctl_handler {
 	unsigned int cmd;
-	int (*func)(struct snd_seq_client *client, void __user * arg);
-} ioctl_tables[] = {
+	int (*func)(struct snd_seq_client *client, void *arg);
+} ioctl_handlers[] = {
+	{ SNDRV_SEQ_IOCTL_PVERSION, snd_seq_ioctl_pversion },
+	{ SNDRV_SEQ_IOCTL_CLIENT_ID, snd_seq_ioctl_client_id },
 	{ SNDRV_SEQ_IOCTL_SYSTEM_INFO, snd_seq_ioctl_system_info },
 	{ SNDRV_SEQ_IOCTL_RUNNING_MODE, snd_seq_ioctl_running_mode },
 	{ SNDRV_SEQ_IOCTL_GET_CLIENT_INFO, snd_seq_ioctl_get_client_info },
@@ -2204,40 +2079,65 @@
 	{ 0, NULL },
 };
 
-static int snd_seq_do_ioctl(struct snd_seq_client *client, unsigned int cmd,
-			    void __user *arg)
-{
-	struct seq_ioctl_table *p;
-
-	switch (cmd) {
-	case SNDRV_SEQ_IOCTL_PVERSION:
-		/* return sequencer version number */
-		return put_user(SNDRV_SEQ_VERSION, (int __user *)arg) ? -EFAULT : 0;
-	case SNDRV_SEQ_IOCTL_CLIENT_ID:
-		/* return the id of this client */
-		return put_user(client->number, (int __user *)arg) ? -EFAULT : 0;
-	}
-
-	if (! arg)
-		return -EFAULT;
-	for (p = ioctl_tables; p->cmd; p++) {
-		if (p->cmd == cmd)
-			return p->func(client, arg);
-	}
-	pr_debug("ALSA: seq unknown ioctl() 0x%x (type='%c', number=0x%02x)\n",
-		   cmd, _IOC_TYPE(cmd), _IOC_NR(cmd));
-	return -ENOTTY;
-}
-
-
-static long snd_seq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+static long snd_seq_ioctl(struct file *file, unsigned int cmd,
+			  unsigned long arg)
 {
 	struct snd_seq_client *client = file->private_data;
+	/* To use kernel stack for ioctl data. */
+	union {
+		int pversion;
+		int client_id;
+		struct snd_seq_system_info	system_info;
+		struct snd_seq_running_info	running_info;
+		struct snd_seq_client_info	client_info;
+		struct snd_seq_port_info	port_info;
+		struct snd_seq_port_subscribe	port_subscribe;
+		struct snd_seq_queue_info	queue_info;
+		struct snd_seq_queue_status	queue_status;
+		struct snd_seq_queue_tempo	tempo;
+		struct snd_seq_queue_timer	queue_timer;
+		struct snd_seq_queue_client	queue_client;
+		struct snd_seq_client_pool	client_pool;
+		struct snd_seq_remove_events	remove_events;
+		struct snd_seq_query_subs	query_subs;
+	} buf;
+	const struct ioctl_handler *handler;
+	unsigned long size;
+	int err;
 
 	if (snd_BUG_ON(!client))
 		return -ENXIO;
-		
-	return snd_seq_do_ioctl(client, cmd, (void __user *) arg);
+
+	for (handler = ioctl_handlers; handler->cmd > 0; ++handler) {
+		if (handler->cmd == cmd)
+			break;
+	}
+	if (handler->cmd == 0)
+		return -ENOTTY;
+
+	memset(&buf, 0, sizeof(buf));
+
+	/*
+	 * All of ioctl commands for ALSA sequencer get an argument of size
+	 * within 13 bits. We can safely pick up the size from the command.
+	 */
+	size = _IOC_SIZE(handler->cmd);
+	if (handler->cmd & IOC_IN) {
+		if (copy_from_user(&buf, (const void __user *)arg, size))
+			return -EFAULT;
+	}
+
+	err = handler->func(client, &buf);
+	if (err >= 0) {
+		/* Some commands includes a bug in 'dir' field. */
+		if (handler->cmd == SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT ||
+		    handler->cmd == SNDRV_SEQ_IOCTL_SET_CLIENT_POOL ||
+		    (handler->cmd & IOC_OUT))
+			if (copy_to_user((void __user *)arg, &buf, size))
+				return -EFAULT;
+	}
+
+	return err;
 }
 
 #ifdef CONFIG_COMPAT
@@ -2423,23 +2323,35 @@
 
 EXPORT_SYMBOL(snd_seq_kernel_client_dispatch);
 
-/*
- * exported, called by kernel clients to perform same functions as with
- * userland ioctl() 
+/**
+ * snd_seq_kernel_client_ctl - operate a command for a client with data in
+ *			       kernel space.
+ * @clientid:	A numerical ID for a client.
+ * @cmd:	An ioctl(2) command for ALSA sequencer operation.
+ * @arg:	A pointer to data in kernel space.
+ *
+ * Against its name, both kernel/application client can be handled by this
+ * kernel API. A pointer of 'arg' argument should be in kernel space.
+ *
+ * Return: 0 at success. Negative error code at failure.
  */
 int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg)
 {
+	const struct ioctl_handler *handler;
 	struct snd_seq_client *client;
-	mm_segment_t fs;
-	int result;
 
 	client = clientptr(clientid);
 	if (client == NULL)
 		return -ENXIO;
-	fs = snd_enter_user();
-	result = snd_seq_do_ioctl(client, cmd, (void __force __user *)arg);
-	snd_leave_user(fs);
-	return result;
+
+	for (handler = ioctl_handlers; handler->cmd > 0; ++handler) {
+		if (handler->cmd == cmd)
+			return handler->func(client, arg);
+	}
+
+	pr_debug("ALSA: seq unknown ioctl() 0x%x (type='%c', number=0x%02x)\n",
+		 cmd, _IOC_TYPE(cmd), _IOC_NR(cmd));
+	return -ENOTTY;
 }
 
 EXPORT_SYMBOL(snd_seq_kernel_client_ctl);
diff --git a/sound/core/seq/seq_compat.c b/sound/core/seq/seq_compat.c
index 6517590..fce5697 100644
--- a/sound/core/seq/seq_compat.c
+++ b/sound/core/seq/seq_compat.c
@@ -47,7 +47,6 @@
 {
 	int err = -EFAULT;
 	struct snd_seq_port_info *data;
-	mm_segment_t fs;
 
 	data = kmalloc(sizeof(*data), GFP_KERNEL);
 	if (!data)
@@ -59,9 +58,7 @@
 		goto error;
 	data->kernel = NULL;
 
-	fs = snd_enter_user();
-	err = snd_seq_do_ioctl(client, cmd, data);
-	snd_leave_user(fs);
+	err = snd_seq_kernel_client_ctl(client->number, cmd, &data);
 	if (err < 0)
 		goto error;
 
@@ -123,7 +120,7 @@
 	case SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION:
 	case SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT:
 	case SNDRV_SEQ_IOCTL_RUNNING_MODE:
-		return snd_seq_do_ioctl(client, cmd, argp);
+		return snd_seq_ioctl(file, cmd, arg);
 	case SNDRV_SEQ_IOCTL_CREATE_PORT32:
 		return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, argp);
 	case SNDRV_SEQ_IOCTL_DELETE_PORT32:
diff --git a/sound/firewire/bebob/Makefile b/sound/firewire/bebob/Makefile
index af7ed66..dd45486 100644
--- a/sound/firewire/bebob/Makefile
+++ b/sound/firewire/bebob/Makefile
@@ -1,4 +1,5 @@
 snd-bebob-objs := bebob_command.o bebob_stream.o bebob_proc.o bebob_midi.o \
-		  bebob_pcm.o bebob_hwdep.o bebob_terratec.o bebob_yamaha.o \
-		  bebob_focusrite.o bebob_maudio.o bebob.o
+		  bebob_pcm.o bebob_hwdep.o bebob_terratec.o \
+		  bebob_yamaha_terratec.o bebob_focusrite.o bebob_maudio.o \
+		  bebob.o
 obj-$(CONFIG_SND_BEBOB) += snd-bebob.o
diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c
index f7e2cbd..3469ac14 100644
--- a/sound/firewire/bebob/bebob.c
+++ b/sound/firewire/bebob/bebob.c
@@ -458,17 +458,17 @@
 	/* TerraTec Electronic GmbH, PHASE 88 Rack FW */
 	SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000003, &phase88_rack_spec),
 	/* TerraTec Electronic GmbH, PHASE 24 FW */
-	SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000004, &phase24_series_spec),
+	SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000004, &yamaha_terratec_spec),
 	/* TerraTec Electronic GmbH, Phase X24 FW */
-	SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000007, &phase24_series_spec),
+	SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000007, &yamaha_terratec_spec),
 	/* TerraTec Electronic GmbH, EWS MIC2/MIC8 */
 	SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000005, &spec_normal),
 	/* Terratec Electronic GmbH, Aureon 7.1 Firewire */
 	SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000002, &spec_normal),
 	/* Yamaha, GO44 */
-	SND_BEBOB_DEV_ENTRY(VEN_YAMAHA, 0x0010000b, &yamaha_go_spec),
+	SND_BEBOB_DEV_ENTRY(VEN_YAMAHA, 0x0010000b, &yamaha_terratec_spec),
 	/* YAMAHA, GO46 */
-	SND_BEBOB_DEV_ENTRY(VEN_YAMAHA, 0x0010000c, &yamaha_go_spec),
+	SND_BEBOB_DEV_ENTRY(VEN_YAMAHA, 0x0010000c, &yamaha_terratec_spec),
 	/* Focusrite, SaffirePro 26 I/O */
 	SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, 0x00000003, &saffirepro_26_spec),
 	/* Focusrite, SaffirePro 10 I/O */
diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h
index e7f1bb9..175da87 100644
--- a/sound/firewire/bebob/bebob.h
+++ b/sound/firewire/bebob/bebob.h
@@ -235,8 +235,7 @@
 
 /* model specific operations */
 extern const struct snd_bebob_spec phase88_rack_spec;
-extern const struct snd_bebob_spec phase24_series_spec;
-extern const struct snd_bebob_spec yamaha_go_spec;
+extern const struct snd_bebob_spec yamaha_terratec_spec;
 extern const struct snd_bebob_spec saffirepro_26_spec;
 extern const struct snd_bebob_spec saffirepro_10_spec;
 extern const struct snd_bebob_spec saffire_le_spec;
diff --git a/sound/firewire/bebob/bebob_terratec.c b/sound/firewire/bebob/bebob_terratec.c
index c38358b..2fdaf93 100644
--- a/sound/firewire/bebob/bebob_terratec.c
+++ b/sound/firewire/bebob/bebob_terratec.c
@@ -36,25 +36,6 @@
 	return err;
 }
 
-static enum snd_bebob_clock_type phase24_series_clk_src_types[] = {
-	SND_BEBOB_CLOCK_TYPE_INTERNAL,
-	SND_BEBOB_CLOCK_TYPE_EXTERNAL,	/* S/PDIF */
-};
-static int
-phase24_series_clk_src_get(struct snd_bebob *bebob, unsigned int *id)
-{
-	int err;
-
-	err = avc_audio_get_selector(bebob->unit, 0, 4, id);
-	if (err < 0)
-		return err;
-
-	if (*id >= ARRAY_SIZE(phase24_series_clk_src_types))
-		return -EIO;
-
-	return 0;
-}
-
 static const struct snd_bebob_rate_spec phase_series_rate_spec = {
 	.get	= &snd_bebob_stream_get_rate,
 	.set	= &snd_bebob_stream_set_rate,
@@ -71,15 +52,3 @@
 	.rate	= &phase_series_rate_spec,
 	.meter	= NULL
 };
-
-/* 'PHASE 24 FW' and 'PHASE X24 FW' */
-static const struct snd_bebob_clock_spec phase24_series_clk = {
-	.num	= ARRAY_SIZE(phase24_series_clk_src_types),
-	.types	= phase24_series_clk_src_types,
-	.get	= &phase24_series_clk_src_get,
-};
-const struct snd_bebob_spec phase24_series_spec = {
-	.clock	= &phase24_series_clk,
-	.rate	= &phase_series_rate_spec,
-	.meter	= NULL
-};
diff --git a/sound/firewire/bebob/bebob_yamaha.c b/sound/firewire/bebob/bebob_yamaha_terratec.c
similarity index 84%
rename from sound/firewire/bebob/bebob_yamaha.c
rename to sound/firewire/bebob/bebob_yamaha_terratec.c
index 90d4404..a6be3e7 100644
--- a/sound/firewire/bebob/bebob_yamaha.c
+++ b/sound/firewire/bebob/bebob_yamaha_terratec.c
@@ -14,7 +14,7 @@
  * must be accompanied. If changing the state, a LED on the device starts to
  * blink and its sync status is false. In this state, the device sounds nothing
  * even if streaming. To start streaming at the current sampling rate is only
- * way to revocer this state. GO46 is better for stand-alone mixer.
+ * way to recover this state. GO46 is better for stand-alone mixer.
  *
  * Both of them have a capability to change its sampling rate up to 192.0kHz.
  * At 192.0kHz, the device reports 4 PCM-in, 1 MIDI-in, 6 PCM-out, 1 MIDI-out.
@@ -25,7 +25,10 @@
  * streaming with many asynchronous transactions brings sounds with noises.
  * Unfortunately current 'ffado-mixer' generated many asynchronous transaction
  * to observe device's state, mainly check cmp connection and signal format. I
- * reccomend users to close ffado-mixer at 192.0kHz if mixer is needless.
+ * recommend users to close ffado-mixer at 192.0kHz if mixer is needless.
+ *
+ * Terratec PHASE 24 FW and PHASE X24 FW are internally the same as
+ * Yamaha GO 44 and GO 46. Yamaha and Terratec had cooperated for these models.
  */
 
 static enum snd_bebob_clock_type clk_src_types[] = {
@@ -55,7 +58,7 @@
 	.get	= &snd_bebob_stream_get_rate,
 	.set	= &snd_bebob_stream_set_rate,
 };
-const struct snd_bebob_spec yamaha_go_spec = {
+const struct snd_bebob_spec yamaha_terratec_spec = {
 	.clock	= &clock_spec,
 	.rate	= &rate_spec,
 	.meter	= NULL
diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c
index 4aa0249..6074fe1 100644
--- a/sound/firewire/dice/dice-pcm.c
+++ b/sound/firewire/dice/dice-pcm.c
@@ -302,7 +302,7 @@
 
 int snd_dice_create_pcm(struct snd_dice *dice)
 {
-	static struct snd_pcm_ops capture_ops = {
+	static const struct snd_pcm_ops capture_ops = {
 		.open      = pcm_open,
 		.close     = pcm_close,
 		.ioctl     = snd_pcm_lib_ioctl,
@@ -314,7 +314,7 @@
 		.page      = snd_pcm_lib_get_vmalloc_page,
 		.mmap      = snd_pcm_lib_mmap_vmalloc,
 	};
-	static struct snd_pcm_ops playback_ops = {
+	static const struct snd_pcm_ops playback_ops = {
 		.open      = pcm_open,
 		.close     = pcm_close,
 		.ioctl     = snd_pcm_lib_ioctl,
diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c
index cac28f7..613f058 100644
--- a/sound/firewire/digi00x/digi00x-pcm.c
+++ b/sound/firewire/digi00x/digi00x-pcm.c
@@ -329,7 +329,7 @@
 	return amdtp_stream_pcm_pointer(&dg00x->rx_stream);
 }
 
-static struct snd_pcm_ops pcm_capture_ops = {
+static const struct snd_pcm_ops pcm_capture_ops = {
 	.open		= pcm_open,
 	.close		= pcm_close,
 	.ioctl		= snd_pcm_lib_ioctl,
@@ -341,7 +341,7 @@
 	.page		= snd_pcm_lib_get_vmalloc_page,
 };
 
-static struct snd_pcm_ops pcm_playback_ops = {
+static const struct snd_pcm_ops pcm_playback_ops = {
 	.open		= pcm_open,
 	.close		= pcm_close,
 	.ioctl		= snd_pcm_lib_ioctl,
diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c
index 8d23341..f3530f8 100644
--- a/sound/firewire/oxfw/oxfw-pcm.c
+++ b/sound/firewire/oxfw/oxfw-pcm.c
@@ -388,7 +388,7 @@
 
 int snd_oxfw_create_pcm(struct snd_oxfw *oxfw)
 {
-	static struct snd_pcm_ops capture_ops = {
+	static const struct snd_pcm_ops capture_ops = {
 		.open      = pcm_open,
 		.close     = pcm_close,
 		.ioctl     = snd_pcm_lib_ioctl,
@@ -400,7 +400,7 @@
 		.page      = snd_pcm_lib_get_vmalloc_page,
 		.mmap      = snd_pcm_lib_mmap_vmalloc,
 	};
-	static struct snd_pcm_ops playback_ops = {
+	static const struct snd_pcm_ops playback_ops = {
 		.open      = pcm_open,
 		.close     = pcm_close,
 		.ioctl     = snd_pcm_lib_ioctl,
diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c
index 380d3db..79db1b6 100644
--- a/sound/firewire/tascam/tascam-pcm.c
+++ b/sound/firewire/tascam/tascam-pcm.c
@@ -268,7 +268,7 @@
 	return amdtp_stream_pcm_pointer(&tscm->rx_stream);
 }
 
-static struct snd_pcm_ops pcm_capture_ops = {
+static const struct snd_pcm_ops pcm_capture_ops = {
 	.open		= pcm_open,
 	.close		= pcm_close,
 	.ioctl		= snd_pcm_lib_ioctl,
@@ -280,7 +280,7 @@
 	.page		= snd_pcm_lib_get_vmalloc_page,
 };
 
-static struct snd_pcm_ops pcm_playback_ops = {
+static const struct snd_pcm_ops pcm_playback_ops = {
 	.open		= pcm_open,
 	.close		= pcm_close,
 	.ioctl		= snd_pcm_lib_ioctl,
diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c
index 860f8ca..2614691 100644
--- a/sound/hda/ext/hdac_ext_controller.c
+++ b/sound/hda/ext/hdac_ext_controller.c
@@ -29,81 +29,6 @@
  */
 #define HDAC_MAX_CAPS 10
 
-/**
- * snd_hdac_ext_bus_parse_capabilities - parse capablity structure
- * @ebus: the pointer to extended bus object
- *
- * Returns 0 if successful, or a negative error code.
- */
-int snd_hdac_ext_bus_parse_capabilities(struct hdac_ext_bus *ebus)
-{
-	unsigned int cur_cap;
-	unsigned int offset;
-	struct hdac_bus *bus = &ebus->bus;
-	unsigned int counter = 0;
-
-	offset = snd_hdac_chip_readl(bus, LLCH);
-
-	/* Lets walk the linked capabilities list */
-	do {
-		cur_cap = _snd_hdac_chip_read(l, bus, offset);
-
-		dev_dbg(bus->dev, "Capability version: 0x%x\n",
-				((cur_cap & AZX_CAP_HDR_VER_MASK) >> AZX_CAP_HDR_VER_OFF));
-
-		dev_dbg(bus->dev, "HDA capability ID: 0x%x\n",
-				(cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF);
-
-		switch ((cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF) {
-		case AZX_ML_CAP_ID:
-			dev_dbg(bus->dev, "Found ML capability\n");
-			ebus->mlcap = bus->remap_addr + offset;
-			break;
-
-		case AZX_GTS_CAP_ID:
-			dev_dbg(bus->dev, "Found GTS capability offset=%x\n", offset);
-			ebus->gtscap = bus->remap_addr + offset;
-			break;
-
-		case AZX_PP_CAP_ID:
-			/* PP capability found, the Audio DSP is present */
-			dev_dbg(bus->dev, "Found PP capability offset=%x\n", offset);
-			ebus->ppcap = bus->remap_addr + offset;
-			break;
-
-		case AZX_SPB_CAP_ID:
-			/* SPIB capability found, handler function */
-			dev_dbg(bus->dev, "Found SPB capability\n");
-			ebus->spbcap = bus->remap_addr + offset;
-			break;
-
-		case AZX_DRSM_CAP_ID:
-			/* DMA resume  capability found, handler function */
-			dev_dbg(bus->dev, "Found DRSM capability\n");
-			ebus->drsmcap = bus->remap_addr + offset;
-			break;
-
-		default:
-			dev_dbg(bus->dev, "Unknown capability %d\n", cur_cap);
-			break;
-		}
-
-		counter++;
-
-		if (counter > HDAC_MAX_CAPS) {
-			dev_err(bus->dev, "We exceeded HDAC Ext capablities!!!\n");
-			break;
-		}
-
-		/* read the offset of next capabiity */
-		offset = cur_cap & AZX_CAP_HDR_NXT_PTR_MASK;
-
-	} while (offset);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_parse_capabilities);
-
 /*
  * processing pipe helpers - these helpers are useful for dealing with HDA
  * new capability of processing pipelines
@@ -118,15 +43,15 @@
 {
 	struct hdac_bus *bus = &ebus->bus;
 
-	if (!ebus->ppcap) {
+	if (!bus->ppcap) {
 		dev_err(bus->dev, "Address of PP capability is NULL");
 		return;
 	}
 
 	if (enable)
-		snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_GPROCEN);
+		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_GPROCEN);
 	else
-		snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_GPROCEN, 0);
+		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_GPROCEN, 0);
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_enable);
 
@@ -139,15 +64,15 @@
 {
 	struct hdac_bus *bus = &ebus->bus;
 
-	if (!ebus->ppcap) {
+	if (!bus->ppcap) {
 		dev_err(bus->dev, "Address of PP capability is NULL\n");
 		return;
 	}
 
 	if (enable)
-		snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_PIE);
+		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_PIE);
 	else
-		snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_PIE, 0);
+		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_PIE, 0);
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_int_enable);
 
@@ -171,7 +96,7 @@
 	struct hdac_ext_link *hlink;
 	struct hdac_bus *bus = &ebus->bus;
 
-	link_count = readl(ebus->mlcap + AZX_REG_ML_MLCD) + 1;
+	link_count = readl(bus->mlcap + AZX_REG_ML_MLCD) + 1;
 
 	dev_dbg(bus->dev, "In %s Link count: %d\n", __func__, link_count);
 
@@ -181,7 +106,7 @@
 			return -ENOMEM;
 		hlink->index = idx;
 		hlink->bus = bus;
-		hlink->ml_addr = ebus->mlcap + AZX_ML_BASE +
+		hlink->ml_addr = bus->mlcap + AZX_ML_BASE +
 					(AZX_ML_INTERVAL * idx);
 		hlink->lcaps  = readl(hlink->ml_addr + AZX_REG_ML_LCAP);
 		hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID);
diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c
index 626f3bb..3be051a 100644
--- a/sound/hda/ext/hdac_ext_stream.c
+++ b/sound/hda/ext/hdac_ext_stream.c
@@ -40,27 +40,27 @@
 {
 	struct hdac_bus *bus = &ebus->bus;
 
-	if (ebus->ppcap) {
-		stream->pphc_addr = ebus->ppcap + AZX_PPHC_BASE +
+	if (bus->ppcap) {
+		stream->pphc_addr = bus->ppcap + AZX_PPHC_BASE +
 				AZX_PPHC_INTERVAL * idx;
 
-		stream->pplc_addr = ebus->ppcap + AZX_PPLC_BASE +
+		stream->pplc_addr = bus->ppcap + AZX_PPLC_BASE +
 				AZX_PPLC_MULTI * ebus->num_streams +
 				AZX_PPLC_INTERVAL * idx;
 	}
 
-	if (ebus->spbcap) {
-		stream->spib_addr = ebus->spbcap + AZX_SPB_BASE +
+	if (bus->spbcap) {
+		stream->spib_addr = bus->spbcap + AZX_SPB_BASE +
 					AZX_SPB_INTERVAL * idx +
 					AZX_SPB_SPIB;
 
-		stream->fifo_addr = ebus->spbcap + AZX_SPB_BASE +
+		stream->fifo_addr = bus->spbcap + AZX_SPB_BASE +
 					AZX_SPB_INTERVAL * idx +
 					AZX_SPB_MAXFIFO;
 	}
 
-	if (ebus->drsmcap)
-		stream->dpibr_addr = ebus->drsmcap + AZX_DRSM_BASE +
+	if (bus->drsmcap)
+		stream->dpibr_addr = bus->drsmcap + AZX_DRSM_BASE +
 					AZX_DRSM_INTERVAL * idx;
 
 	stream->decoupled = false;
@@ -131,10 +131,10 @@
 
 	spin_lock_irq(&bus->reg_lock);
 	if (decouple)
-		snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, 0,
+		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0,
 				AZX_PPCTL_PROCEN(hstream->index));
 	else
-		snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL,
+		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
 					AZX_PPCTL_PROCEN(hstream->index), 0);
 	stream->decoupled = decouple;
 	spin_unlock_irq(&bus->reg_lock);
@@ -255,7 +255,7 @@
 	struct hdac_stream *stream = NULL;
 	struct hdac_bus *hbus = &ebus->bus;
 
-	if (!ebus->ppcap) {
+	if (!hbus->ppcap) {
 		dev_err(hbus->dev, "stream type not supported\n");
 		return NULL;
 	}
@@ -296,7 +296,7 @@
 	struct hdac_stream *stream = NULL;
 	struct hdac_bus *hbus = &ebus->bus;
 
-	if (!ebus->ppcap) {
+	if (!hbus->ppcap) {
 		dev_err(hbus->dev, "stream type not supported\n");
 		return NULL;
 	}
@@ -423,21 +423,21 @@
 	u32 register_mask = 0;
 	struct hdac_bus *bus = &ebus->bus;
 
-	if (!ebus->spbcap) {
-		dev_err(bus->dev, "Address of SPB capability is NULL");
+	if (!bus->spbcap) {
+		dev_err(bus->dev, "Address of SPB capability is NULL\n");
 		return;
 	}
 
 	mask |= (1 << index);
 
-	register_mask = readl(ebus->spbcap + AZX_REG_SPB_SPBFCCTL);
+	register_mask = readl(bus->spbcap + AZX_REG_SPB_SPBFCCTL);
 
 	mask |= register_mask;
 
 	if (enable)
-		snd_hdac_updatel(ebus->spbcap, AZX_REG_SPB_SPBFCCTL, 0, mask);
+		snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, 0, mask);
 	else
-		snd_hdac_updatel(ebus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0);
+		snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0);
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_spbcap_enable);
 
@@ -452,8 +452,8 @@
 {
 	struct hdac_bus *bus = &ebus->bus;
 
-	if (!ebus->spbcap) {
-		dev_err(bus->dev, "Address of SPB capability is NULL");
+	if (!bus->spbcap) {
+		dev_err(bus->dev, "Address of SPB capability is NULL\n");
 		return -EINVAL;
 	}
 
@@ -475,8 +475,8 @@
 {
 	struct hdac_bus *bus = &ebus->bus;
 
-	if (!ebus->spbcap) {
-		dev_err(bus->dev, "Address of SPB capability is NULL");
+	if (!bus->spbcap) {
+		dev_err(bus->dev, "Address of SPB capability is NULL\n");
 		return -EINVAL;
 	}
 
@@ -515,21 +515,21 @@
 	u32 register_mask = 0;
 	struct hdac_bus *bus = &ebus->bus;
 
-	if (!ebus->drsmcap) {
-		dev_err(bus->dev, "Address of DRSM capability is NULL");
+	if (!bus->drsmcap) {
+		dev_err(bus->dev, "Address of DRSM capability is NULL\n");
 		return;
 	}
 
 	mask |= (1 << index);
 
-	register_mask = readl(ebus->drsmcap + AZX_REG_SPB_SPBFCCTL);
+	register_mask = readl(bus->drsmcap + AZX_REG_SPB_SPBFCCTL);
 
 	mask |= register_mask;
 
 	if (enable)
-		snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, 0, mask);
+		snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, 0, mask);
 	else
-		snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, mask, 0);
+		snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, 0);
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable);
 
@@ -544,8 +544,8 @@
 {
 	struct hdac_bus *bus = &ebus->bus;
 
-	if (!ebus->drsmcap) {
-		dev_err(bus->dev, "Address of DRSM capability is NULL");
+	if (!bus->drsmcap) {
+		dev_err(bus->dev, "Address of DRSM capability is NULL\n");
 		return -EINVAL;
 	}
 
diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c
index 9fee464..0430658 100644
--- a/sound/hda/hdac_controller.c
+++ b/sound/hda/hdac_controller.c
@@ -255,6 +255,81 @@
 }
 EXPORT_SYMBOL_GPL(snd_hdac_bus_get_response);
 
+#define HDAC_MAX_CAPS 10
+/**
+ * snd_hdac_bus_parse_capabilities - parse capability structure
+ * @bus: the pointer to bus object
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus)
+{
+	unsigned int cur_cap;
+	unsigned int offset;
+	unsigned int counter = 0;
+
+	offset = snd_hdac_chip_readl(bus, LLCH);
+
+	/* Lets walk the linked capabilities list */
+	do {
+		cur_cap = _snd_hdac_chip_read(l, bus, offset);
+
+		dev_dbg(bus->dev, "Capability version: 0x%x\n",
+			(cur_cap & AZX_CAP_HDR_VER_MASK) >> AZX_CAP_HDR_VER_OFF);
+
+		dev_dbg(bus->dev, "HDA capability ID: 0x%x\n",
+			(cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF);
+
+		switch ((cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF) {
+		case AZX_ML_CAP_ID:
+			dev_dbg(bus->dev, "Found ML capability\n");
+			bus->mlcap = bus->remap_addr + offset;
+			break;
+
+		case AZX_GTS_CAP_ID:
+			dev_dbg(bus->dev, "Found GTS capability offset=%x\n", offset);
+			bus->gtscap = bus->remap_addr + offset;
+			break;
+
+		case AZX_PP_CAP_ID:
+			/* PP capability found, the Audio DSP is present */
+			dev_dbg(bus->dev, "Found PP capability offset=%x\n", offset);
+			bus->ppcap = bus->remap_addr + offset;
+			break;
+
+		case AZX_SPB_CAP_ID:
+			/* SPIB capability found, handler function */
+			dev_dbg(bus->dev, "Found SPB capability\n");
+			bus->spbcap = bus->remap_addr + offset;
+			break;
+
+		case AZX_DRSM_CAP_ID:
+			/* DMA resume  capability found, handler function */
+			dev_dbg(bus->dev, "Found DRSM capability\n");
+			bus->drsmcap = bus->remap_addr + offset;
+			break;
+
+		default:
+			dev_dbg(bus->dev, "Unknown capability %d\n", cur_cap);
+			break;
+		}
+
+		counter++;
+
+		if (counter > HDAC_MAX_CAPS) {
+			dev_err(bus->dev, "We exceeded HDAC capabilities!!!\n");
+			break;
+		}
+
+		/* read the offset of next capability */
+		offset = cur_cap & AZX_CAP_HDR_NXT_PTR_MASK;
+
+	} while (offset);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_bus_parse_capabilities);
+
 /*
  * Lowlevel interface
  */
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index 1fc6d8b..8c36990 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -571,7 +571,7 @@
 	return bytes_to_frames(ss->runtime, ptr);
 }
 
-static struct snd_pcm_ops snd_ad1889_playback_ops = {
+static const struct snd_pcm_ops snd_ad1889_playback_ops = {
 	.open = snd_ad1889_playback_open,
 	.close = snd_ad1889_playback_close,
 	.ioctl = snd_pcm_lib_ioctl,
@@ -582,7 +582,7 @@
 	.pointer = snd_ad1889_playback_pointer, 
 };
 
-static struct snd_pcm_ops snd_ad1889_capture_ops = {
+static const struct snd_pcm_ops snd_ad1889_capture_ops = {
 	.open = snd_ad1889_capture_open,
 	.close = snd_ad1889_capture_close,
 	.ioctl = snd_pcm_lib_ioctl,
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index 36470af..92b819e 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -1408,6 +1408,7 @@
 	spin_unlock(&codec->reg_lock);
 	dev_dbg(codec->card->dev, "playback pointer returned cso=%xh.\n", cso);
 
+	cso %= runtime->buffer_size;
 	return cso;
 }
 
@@ -1428,6 +1429,7 @@
 	cso = inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2));
 	spin_unlock(&codec->reg_lock);
 
+	cso %= runtime->buffer_size;
 	return cso;
 }
 
diff --git a/sound/pci/als300.c b/sound/pci/als300.c
index add3176..ab75601 100644
--- a/sound/pci/als300.c
+++ b/sound/pci/als300.c
@@ -563,7 +563,7 @@
 	return bytes_to_frames(substream->runtime, current_ptr);
 }
 
-static struct snd_pcm_ops snd_als300_playback_ops = {
+static const struct snd_pcm_ops snd_als300_playback_ops = {
 	.open =		snd_als300_playback_open,
 	.close =	snd_als300_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -574,7 +574,7 @@
 	.pointer =	snd_als300_pointer,
 };
 
-static struct snd_pcm_ops snd_als300_capture_ops = {
+static const struct snd_pcm_ops snd_als300_capture_ops = {
 	.open =		snd_als300_capture_open,
 	.close =	snd_als300_capture_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index ff39a0c..edabe13 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -672,7 +672,7 @@
 
 /******************************************************************/
 
-static struct snd_pcm_ops snd_als4000_playback_ops = {
+static const struct snd_pcm_ops snd_als4000_playback_ops = {
 	.open =		snd_als4000_playback_open,
 	.close =	snd_als4000_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -683,7 +683,7 @@
 	.pointer =	snd_als4000_playback_pointer
 };
 
-static struct snd_pcm_ops snd_als4000_capture_ops = {
+static const struct snd_pcm_ops snd_als4000_capture_ops = {
 	.open =		snd_als4000_capture_open,
 	.close =	snd_als4000_capture_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index 1039ecc..976a3d2 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -1138,7 +1138,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_card_asihpi_playback_mmap_ops = {
+static const struct snd_pcm_ops snd_card_asihpi_playback_mmap_ops = {
 	.open = snd_card_asihpi_playback_open,
 	.close = snd_card_asihpi_playback_close,
 	.ioctl = snd_card_asihpi_playback_ioctl,
@@ -1305,7 +1305,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = {
+static const struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = {
 	.open = snd_card_asihpi_capture_open,
 	.close = snd_card_asihpi_capture_close,
 	.ioctl = snd_card_asihpi_capture_ioctl,
diff --git a/sound/pci/asihpi/hpifunc.c b/sound/pci/asihpi/hpifunc.c
index 510e56c..f9b5764 100644
--- a/sound/pci/asihpi/hpifunc.c
+++ b/sound/pci/asihpi/hpifunc.c
@@ -2323,11 +2323,8 @@
 u16 hpi_sample_clock_query_local_rate(const u32 h_clock, const u32 index,
 	u32 *prate)
 {
-	u16 err;
-	err = hpi_control_query(h_clock, HPI_SAMPLECLOCK_LOCAL_SAMPLERATE,
-		index, 0, prate);
-
-	return err;
+	return hpi_control_query(h_clock, HPI_SAMPLECLOCK_LOCAL_SAMPLERATE,
+				 index, 0, prate);
 }
 
 u16 hpi_sample_clock_set_local_rate(u32 h_control, u32 sample_rate)
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 2ce0022..a40c918 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -1148,7 +1148,7 @@
 }
 
 /* AC97 playback */
-static struct snd_pcm_ops snd_atiixp_playback_ops = {
+static const struct snd_pcm_ops snd_atiixp_playback_ops = {
 	.open =		snd_atiixp_playback_open,
 	.close =	snd_atiixp_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1160,7 +1160,7 @@
 };
 
 /* AC97 capture */
-static struct snd_pcm_ops snd_atiixp_capture_ops = {
+static const struct snd_pcm_ops snd_atiixp_capture_ops = {
 	.open =		snd_atiixp_capture_open,
 	.close =	snd_atiixp_capture_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1172,7 +1172,7 @@
 };
 
 /* SPDIF playback */
-static struct snd_pcm_ops snd_atiixp_spdif_ops = {
+static const struct snd_pcm_ops snd_atiixp_spdif_ops = {
 	.open =		snd_atiixp_spdif_open,
 	.close =	snd_atiixp_spdif_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index c534552..40152fe 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -947,7 +947,7 @@
 
 
 /* AC97 playback */
-static struct snd_pcm_ops snd_atiixp_playback_ops = {
+static const struct snd_pcm_ops snd_atiixp_playback_ops = {
 	.open =		snd_atiixp_playback_open,
 	.close =	snd_atiixp_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -959,7 +959,7 @@
 };
 
 /* AC97 capture */
-static struct snd_pcm_ops snd_atiixp_capture_ops = {
+static const struct snd_pcm_ops snd_atiixp_capture_ops = {
 	.open =		snd_atiixp_capture_open,
 	.close =	snd_atiixp_capture_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
index d3125c1..e1af24f 100644
--- a/sound/pci/au88x0/au88x0_core.c
+++ b/sound/pci/au88x0/au88x0_core.c
@@ -1043,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))
-			dev_err(vortex->card->dev, "bad adb fifo reset!");
+			dev_err(vortex->card->dev, "bad adb fifo reset!\n");
 		vortex_fifo_clearadbdata(vortex, x, FIFO_SIZE);
 		addr -= 4;
 	}
diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c
index 1677143..57bbb87 100644
--- a/sound/pci/aw2/aw2-alsa.c
+++ b/sound/pci/aw2/aw2-alsa.c
@@ -179,7 +179,7 @@
 module_pci_driver(aw2_driver);
 
 /* operators for playback PCM alsa interface */
-static struct snd_pcm_ops snd_aw2_playback_ops = {
+static const struct snd_pcm_ops snd_aw2_playback_ops = {
 	.open = snd_aw2_pcm_playback_open,
 	.close = snd_aw2_pcm_playback_close,
 	.ioctl = snd_pcm_lib_ioctl,
@@ -191,7 +191,7 @@
 };
 
 /* operators for capture PCM alsa interface */
-static struct snd_pcm_ops snd_aw2_capture_ops = {
+static const struct snd_pcm_ops snd_aw2_capture_ops = {
 	.open = snd_aw2_pcm_capture_open,
 	.close = snd_aw2_pcm_capture_close,
 	.ioctl = snd_pcm_lib_ioctl,
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 5e2ef0b..80c4a44 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -2090,7 +2090,7 @@
 
 /******************************************************************/
 
-static struct snd_pcm_ops snd_azf3328_playback_ops = {
+static const struct snd_pcm_ops snd_azf3328_playback_ops = {
 	.open =		snd_azf3328_pcm_playback_open,
 	.close =	snd_azf3328_pcm_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -2101,7 +2101,7 @@
 	.pointer =	snd_azf3328_pcm_pointer
 };
 
-static struct snd_pcm_ops snd_azf3328_capture_ops = {
+static const struct snd_pcm_ops snd_azf3328_capture_ops = {
 	.open =		snd_azf3328_pcm_capture_open,
 	.close =	snd_azf3328_pcm_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -2112,7 +2112,7 @@
 	.pointer =	snd_azf3328_pcm_pointer
 };
 
-static struct snd_pcm_ops snd_azf3328_i2s_out_ops = {
+static const struct snd_pcm_ops snd_azf3328_i2s_out_ops = {
 	.open =		snd_azf3328_pcm_i2s_out_open,
 	.close =	snd_azf3328_pcm_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index 5925b71..f2c0709 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -550,7 +550,7 @@
 	return (snd_pcm_uframes_t)bytes_to_frames(runtime, chip->current_line * chip->line_bytes);
 }
 
-static struct snd_pcm_ops snd_bt87x_pcm_ops = {
+static const struct snd_pcm_ops snd_bt87x_pcm_ops = {
 	.open = snd_bt87x_pcm_open,
 	.close = snd_bt87x_close,
 	.ioctl = snd_pcm_lib_ioctl,
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index d3cd956..6165a57 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -1109,7 +1109,7 @@
 }
 
 /* operators */
-static struct snd_pcm_ops snd_ca0106_playback_front_ops = {
+static const struct snd_pcm_ops snd_ca0106_playback_front_ops = {
 	.open =        snd_ca0106_pcm_open_playback_front,
 	.close =       snd_ca0106_pcm_close_playback,
 	.ioctl =       snd_pcm_lib_ioctl,
@@ -1120,7 +1120,7 @@
 	.pointer =     snd_ca0106_pcm_pointer_playback,
 };
 
-static struct snd_pcm_ops snd_ca0106_capture_0_ops = {
+static const struct snd_pcm_ops snd_ca0106_capture_0_ops = {
 	.open =        snd_ca0106_pcm_open_0_capture,
 	.close =       snd_ca0106_pcm_close_capture,
 	.ioctl =       snd_pcm_lib_ioctl,
@@ -1131,7 +1131,7 @@
 	.pointer =     snd_ca0106_pcm_pointer_capture,
 };
 
-static struct snd_pcm_ops snd_ca0106_capture_1_ops = {
+static const struct snd_pcm_ops snd_ca0106_capture_1_ops = {
 	.open =        snd_ca0106_pcm_open_1_capture,
 	.close =       snd_ca0106_pcm_close_capture,
 	.ioctl =       snd_pcm_lib_ioctl,
@@ -1142,7 +1142,7 @@
 	.pointer =     snd_ca0106_pcm_pointer_capture,
 };
 
-static struct snd_pcm_ops snd_ca0106_capture_2_ops = {
+static const struct snd_pcm_ops snd_ca0106_capture_2_ops = {
 	.open =        snd_ca0106_pcm_open_2_capture,
 	.close =       snd_ca0106_pcm_close_capture,
 	.ioctl =       snd_pcm_lib_ioctl,
@@ -1153,7 +1153,7 @@
 	.pointer =     snd_ca0106_pcm_pointer_capture,
 };
 
-static struct snd_pcm_ops snd_ca0106_capture_3_ops = {
+static const struct snd_pcm_ops snd_ca0106_capture_3_ops = {
 	.open =        snd_ca0106_pcm_open_3_capture,
 	.close =       snd_ca0106_pcm_close_capture,
 	.ioctl =       snd_pcm_lib_ioctl,
@@ -1164,7 +1164,7 @@
 	.pointer =     snd_ca0106_pcm_pointer_capture,
 };
 
-static struct snd_pcm_ops snd_ca0106_playback_center_lfe_ops = {
+static const struct snd_pcm_ops snd_ca0106_playback_center_lfe_ops = {
         .open =         snd_ca0106_pcm_open_playback_center_lfe,
         .close =        snd_ca0106_pcm_close_playback,
         .ioctl =        snd_pcm_lib_ioctl,
@@ -1175,7 +1175,7 @@
         .pointer =      snd_ca0106_pcm_pointer_playback, 
 };
 
-static struct snd_pcm_ops snd_ca0106_playback_unknown_ops = {
+static const struct snd_pcm_ops snd_ca0106_playback_unknown_ops = {
         .open =         snd_ca0106_pcm_open_playback_unknown,
         .close =        snd_ca0106_pcm_close_playback,
         .ioctl =        snd_pcm_lib_ioctl,
@@ -1186,7 +1186,7 @@
         .pointer =      snd_ca0106_pcm_pointer_playback, 
 };
 
-static struct snd_pcm_ops snd_ca0106_playback_rear_ops = {
+static const struct snd_pcm_ops snd_ca0106_playback_rear_ops = {
         .open =         snd_ca0106_pcm_open_playback_rear,
         .close =        snd_ca0106_pcm_close_playback,
         .ioctl =        snd_pcm_lib_ioctl,
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index 24cdcba..73f5935 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -1838,7 +1838,7 @@
 /*
  */
 
-static struct snd_pcm_ops snd_cmipci_playback_ops = {
+static const struct snd_pcm_ops snd_cmipci_playback_ops = {
 	.open =		snd_cmipci_playback_open,
 	.close =	snd_cmipci_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1849,7 +1849,7 @@
 	.pointer =	snd_cmipci_playback_pointer,
 };
 
-static struct snd_pcm_ops snd_cmipci_capture_ops = {
+static const struct snd_pcm_ops snd_cmipci_capture_ops = {
 	.open =		snd_cmipci_capture_open,
 	.close =	snd_cmipci_capture_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1860,7 +1860,7 @@
 	.pointer =	snd_cmipci_capture_pointer,
 };
 
-static struct snd_pcm_ops snd_cmipci_playback2_ops = {
+static const struct snd_pcm_ops snd_cmipci_playback2_ops = {
 	.open =		snd_cmipci_playback2_open,
 	.close =	snd_cmipci_playback2_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1871,7 +1871,7 @@
 	.pointer =	snd_cmipci_capture_pointer,	/* channel B */
 };
 
-static struct snd_pcm_ops snd_cmipci_playback_spdif_ops = {
+static const struct snd_pcm_ops snd_cmipci_playback_spdif_ops = {
 	.open =		snd_cmipci_playback_spdif_open,
 	.close =	snd_cmipci_playback_spdif_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1882,7 +1882,7 @@
 	.pointer =	snd_cmipci_playback_pointer,
 };
 
-static struct snd_pcm_ops snd_cmipci_capture_spdif_ops = {
+static const struct snd_pcm_ops snd_cmipci_capture_spdif_ops = {
 	.open =		snd_cmipci_capture_spdif_open,
 	.close =	snd_cmipci_capture_spdif_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index c296fd0..615d8a9 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -951,7 +951,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_cs4281_playback_ops = {
+static const struct snd_pcm_ops snd_cs4281_playback_ops = {
 	.open =		snd_cs4281_playback_open,
 	.close =	snd_cs4281_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -962,7 +962,7 @@
 	.pointer =	snd_cs4281_pointer,
 };
 
-static struct snd_pcm_ops snd_cs4281_capture_ops = {
+static const struct snd_pcm_ops snd_cs4281_capture_ops = {
 	.open =		snd_cs4281_capture_open,
 	.close =	snd_cs4281_capture_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index 2706f27..528102c 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -2460,7 +2460,7 @@
 		udelay(10);
 		if (snd_cs46xx_codec_read(chip, AC97_RESET, codec) & 0x8000) {
 			dev_dbg(chip->card->dev,
-				"seconadry codec not present\n");
+				"secondary codec not present\n");
 			return -ENXIO;
 		}
 	}
@@ -2503,7 +2503,7 @@
 	chip->nr_ac97_codecs = 1;
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-	dev_dbg(chip->card->dev, "detecting seconadry codec\n");
+	dev_dbg(chip->card->dev, "detecting secondary codec\n");
 	/* try detect a secondary codec */
 	if (! cs46xx_detect_codec(chip, CS46XX_SECONDARY_CODEC_INDEX))
 		chip->nr_ac97_codecs = 2;
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c
index d2951ed..4a0cbd2 100644
--- a/sound/pci/cs46xx/dsp_spos.c
+++ b/sound/pci/cs46xx/dsp_spos.c
@@ -1441,7 +1441,7 @@
 	
 	if (chip->nr_ac97_codecs == 2) {
 		/* create CODEC tasklet for rear Center/LFE output 
-		   slot 6 and 9 on seconadry CODEC */
+		   slot 6 and 9 on secondary CODEC */
 		clfe_codec_out_scb = cs46xx_dsp_create_codec_out_scb(chip,"CodecOutSCB_CLFE",0x0030,0x0030,
 								     CLFE_MIXER_SCB_ADDR,
 								     CLFE_CODEC_SCB_ADDR,
diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c
index 27fa57d..c208c1d 100644
--- a/sound/pci/cs5535audio/cs5535audio_pcm.c
+++ b/sound/pci/cs5535audio/cs5535audio_pcm.c
@@ -380,7 +380,7 @@
 				 substream->runtime->rate);
 }
 
-static struct snd_pcm_ops snd_cs5535audio_playback_ops = {
+static const struct snd_pcm_ops snd_cs5535audio_playback_ops = {
 	.open =		snd_cs5535audio_playback_open,
 	.close =	snd_cs5535audio_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -391,7 +391,7 @@
 	.pointer =	snd_cs5535audio_pcm_pointer,
 };
 
-static struct snd_pcm_ops snd_cs5535audio_capture_ops = {
+static const struct snd_pcm_ops snd_cs5535audio_capture_ops = {
 	.open =		snd_cs5535audio_capture_open,
 	.close =	snd_cs5535audio_capture_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
index 977a598..908658a 100644
--- a/sound/pci/ctxfi/ctatc.c
+++ b/sound/pci/ctxfi/ctatc.c
@@ -1623,7 +1623,7 @@
 }
 #endif
 
-static struct ct_atc atc_preset = {
+static const struct ct_atc atc_preset = {
 	.map_audio_buffer = ct_map_audio_buffer,
 	.unmap_audio_buffer = ct_unmap_audio_buffer,
 	.pcm_playback_prepare = atc_pcm_playback_prepare,
diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c
index d86c474..9749780 100644
--- a/sound/pci/ctxfi/ctpcm.c
+++ b/sound/pci/ctxfi/ctpcm.c
@@ -372,7 +372,7 @@
 }
 
 /* PCM operators for playback */
-static struct snd_pcm_ops ct_pcm_playback_ops = {
+static const struct snd_pcm_ops ct_pcm_playback_ops = {
 	.open	 	= ct_pcm_playback_open,
 	.close		= ct_pcm_playback_close,
 	.ioctl		= snd_pcm_lib_ioctl,
@@ -385,7 +385,7 @@
 };
 
 /* PCM operators for capture */
-static struct snd_pcm_ops ct_pcm_capture_ops = {
+static const struct snd_pcm_ops ct_pcm_capture_ops = {
 	.open	 	= ct_pcm_capture_open,
 	.close		= ct_pcm_capture_close,
 	.ioctl		= snd_pcm_lib_ioctl,
diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c
index 419306e..520e19b 100644
--- a/sound/pci/ctxfi/ctvmem.c
+++ b/sound/pci/ctxfi/ctvmem.c
@@ -166,11 +166,7 @@
 static dma_addr_t
 ct_get_ptp_phys(struct ct_vm *vm, int index)
 {
-	dma_addr_t addr;
-
-	addr = (index >= CT_PTP_NUM) ? ~0UL : vm->ptp[index].addr;
-
-	return addr;
+	return (index >= CT_PTP_NUM) ? ~0UL : vm->ptp[index].addr;
 }
 
 int ct_vm_create(struct ct_vm **rvm, struct pci_dev *pci)
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 6d1b98d..921037e 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -548,7 +548,7 @@
 }
 
 /* operators */
-static struct snd_pcm_ops snd_emu10k1x_playback_ops = {
+static const struct snd_pcm_ops snd_emu10k1x_playback_ops = {
 	.open =        snd_emu10k1x_playback_open,
 	.close =       snd_emu10k1x_playback_close,
 	.ioctl =       snd_pcm_lib_ioctl,
@@ -694,7 +694,7 @@
 	return ptr;
 }
 
-static struct snd_pcm_ops snd_emu10k1x_capture_ops = {
+static const struct snd_pcm_ops snd_emu10k1x_capture_ops = {
 	.open =        snd_emu10k1x_pcm_open_capture,
 	.close =       snd_emu10k1x_pcm_close_capture,
 	.ioctl =       snd_pcm_lib_ioctl,
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
index 14a305b..37be1e1 100644
--- a/sound/pci/emu10k1/emupcm.c
+++ b/sound/pci/emu10k1/emupcm.c
@@ -1364,7 +1364,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_emu10k1_playback_ops = {
+static const struct snd_pcm_ops snd_emu10k1_playback_ops = {
 	.open =			snd_emu10k1_playback_open,
 	.close =		snd_emu10k1_playback_close,
 	.ioctl =		snd_pcm_lib_ioctl,
@@ -1376,7 +1376,7 @@
 	.page =			snd_pcm_sgbuf_ops_page,
 };
 
-static struct snd_pcm_ops snd_emu10k1_capture_ops = {
+static const struct snd_pcm_ops snd_emu10k1_capture_ops = {
 	.open =			snd_emu10k1_capture_open,
 	.close =		snd_emu10k1_capture_close,
 	.ioctl =		snd_pcm_lib_ioctl,
@@ -1388,7 +1388,7 @@
 };
 
 /* EFX playback */
-static struct snd_pcm_ops snd_emu10k1_efx_playback_ops = {
+static const struct snd_pcm_ops snd_emu10k1_efx_playback_ops = {
 	.open =			snd_emu10k1_efx_playback_open,
 	.close =		snd_emu10k1_efx_playback_close,
 	.ioctl =		snd_pcm_lib_ioctl,
@@ -1455,7 +1455,7 @@
 }
 
 
-static struct snd_pcm_ops snd_emu10k1_capture_mic_ops = {
+static const struct snd_pcm_ops snd_emu10k1_capture_mic_ops = {
 	.open =			snd_emu10k1_capture_mic_open,
 	.close =		snd_emu10k1_capture_mic_close,
 	.ioctl =		snd_pcm_lib_ioctl,
@@ -1550,7 +1550,7 @@
 	.put = snd_emu10k1_pcm_efx_voices_mask_put
 };
 
-static struct snd_pcm_ops snd_emu10k1_capture_efx_ops = {
+static const struct snd_pcm_ops snd_emu10k1_capture_efx_ops = {
 	.open =			snd_emu10k1_capture_efx_open,
 	.close =		snd_emu10k1_capture_efx_close,
 	.ioctl =		snd_pcm_lib_ioctl,
@@ -1791,7 +1791,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_emu10k1_fx8010_playback_ops = {
+static const struct snd_pcm_ops snd_emu10k1_fx8010_playback_ops = {
 	.open =			snd_emu10k1_fx8010_playback_open,
 	.close =		snd_emu10k1_fx8010_playback_close,
 	.ioctl =		snd_pcm_lib_ioctl,
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c
index 3c60b43..c11f1a2 100644
--- a/sound/pci/emu10k1/p16v.c
+++ b/sound/pci/emu10k1/p16v.c
@@ -300,37 +300,29 @@
 static int snd_p16v_pcm_hw_params_playback(struct snd_pcm_substream *substream,
 				      struct snd_pcm_hw_params *hw_params)
 {
-	int result;
-	result = snd_pcm_lib_malloc_pages(substream,
+	return snd_pcm_lib_malloc_pages(substream,
 					params_buffer_bytes(hw_params));
-	return result;
 }
 
 /* hw_params callback */
 static int snd_p16v_pcm_hw_params_capture(struct snd_pcm_substream *substream,
 				      struct snd_pcm_hw_params *hw_params)
 {
-	int result;
-	result = snd_pcm_lib_malloc_pages(substream,
+	return snd_pcm_lib_malloc_pages(substream,
 					params_buffer_bytes(hw_params));
-	return result;
 }
 
 
 /* hw_free callback */
 static int snd_p16v_pcm_hw_free_playback(struct snd_pcm_substream *substream)
 {
-	int result;
-	result = snd_pcm_lib_free_pages(substream);
-	return result;
+	return snd_pcm_lib_free_pages(substream);
 }
 
 /* hw_free callback */
 static int snd_p16v_pcm_hw_free_capture(struct snd_pcm_substream *substream)
 {
-	int result;
-	result = snd_pcm_lib_free_pages(substream);
-	return result;
+	return snd_pcm_lib_free_pages(substream);
 }
 
 
@@ -601,7 +593,7 @@
 }
 
 /* operators */
-static struct snd_pcm_ops snd_p16v_playback_front_ops = {
+static const struct snd_pcm_ops snd_p16v_playback_front_ops = {
 	.open =        snd_p16v_pcm_open_playback_front,
 	.close =       snd_p16v_pcm_close_playback,
 	.ioctl =       snd_pcm_lib_ioctl,
@@ -612,7 +604,7 @@
 	.pointer =     snd_p16v_pcm_pointer_playback,
 };
 
-static struct snd_pcm_ops snd_p16v_capture_ops = {
+static const struct snd_pcm_ops snd_p16v_capture_ops = {
 	.open =        snd_p16v_pcm_open_capture,
 	.close =       snd_p16v_pcm_close_capture,
 	.ioctl =       snd_pcm_lib_ioctl,
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index 626cd21..7e760fe 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -1227,7 +1227,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_ensoniq_playback1_ops = {
+static const struct snd_pcm_ops snd_ensoniq_playback1_ops = {
 	.open =		snd_ensoniq_playback1_open,
 	.close =	snd_ensoniq_playback1_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1238,7 +1238,7 @@
 	.pointer =	snd_ensoniq_playback1_pointer,
 };
 
-static struct snd_pcm_ops snd_ensoniq_playback2_ops = {
+static const struct snd_pcm_ops snd_ensoniq_playback2_ops = {
 	.open =		snd_ensoniq_playback2_open,
 	.close =	snd_ensoniq_playback2_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1249,7 +1249,7 @@
 	.pointer =	snd_ensoniq_playback2_pointer,
 };
 
-static struct snd_pcm_ops snd_ensoniq_capture_ops = {
+static const struct snd_pcm_ops snd_ensoniq_capture_ops = {
 	.open =		snd_ensoniq_capture_open,
 	.close =	snd_ensoniq_capture_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 8963d76..6813558 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -992,7 +992,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_es1938_playback_ops = {
+static const struct snd_pcm_ops snd_es1938_playback_ops = {
 	.open =		snd_es1938_playback_open,
 	.close =	snd_es1938_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1003,7 +1003,7 @@
 	.pointer =	snd_es1938_playback_pointer,
 };
 
-static struct snd_pcm_ops snd_es1938_capture_ops = {
+static const struct snd_pcm_ops snd_es1938_capture_ops = {
 	.open =		snd_es1938_capture_open,
 	.close =	snd_es1938_capture_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index 514f260..8146fb7 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -1677,7 +1677,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_es1968_playback_ops = {
+static const struct snd_pcm_ops snd_es1968_playback_ops = {
 	.open =		snd_es1968_playback_open,
 	.close =	snd_es1968_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1688,7 +1688,7 @@
 	.pointer =	snd_es1968_pcm_pointer,
 };
 
-static struct snd_pcm_ops snd_es1968_capture_ops = {
+static const struct snd_pcm_ops snd_es1968_capture_ops = {
 	.open =		snd_es1968_capture_open,
 	.close =	snd_es1968_capture_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index bade9b9..c47287d 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -691,7 +691,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_fm801_playback_ops = {
+static const struct snd_pcm_ops snd_fm801_playback_ops = {
 	.open =		snd_fm801_playback_open,
 	.close =	snd_fm801_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -702,7 +702,7 @@
 	.pointer =	snd_fm801_playback_pointer,
 };
 
-static struct snd_pcm_ops snd_fm801_capture_ops = {
+static const struct snd_pcm_ops snd_fm801_capture_ops = {
 	.open =		snd_fm801_capture_open,
 	.close =	snd_fm801_capture_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
index 27de801..5008785 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/pci/hda/hda_controller.c
@@ -27,6 +27,12 @@
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
+
+#ifdef CONFIG_X86
+/* for art-tsc conversion */
+#include <asm/tsc.h>
+#endif
+
 #include <sound/core.h>
 #include <sound/initval.h>
 #include "hda_controller.h"
@@ -337,12 +343,173 @@
 			       azx_get_position(chip, azx_dev));
 }
 
+/*
+ * azx_scale64: Scale base by mult/div while not overflowing sanely
+ *
+ * Derived from scale64_check_overflow in kernel/time/timekeeping.c
+ *
+ * The tmestamps for a 48Khz stream can overflow after (2^64/10^9)/48K which
+ * is about 384307 ie ~4.5 days.
+ *
+ * This scales the calculation so that overflow will happen but after 2^64 /
+ * 48000 secs, which is pretty large!
+ *
+ * In caln below:
+ *	base may overflow, but since there isn’t any additional division
+ *	performed on base it’s OK
+ *	rem can’t overflow because both are 32-bit values
+ */
+
+#ifdef CONFIG_X86
+static u64 azx_scale64(u64 base, u32 num, u32 den)
+{
+	u64 rem;
+
+	rem = do_div(base, den);
+
+	base *= num;
+	rem *= num;
+
+	do_div(rem, den);
+
+	return base + rem;
+}
+
+static int azx_get_sync_time(ktime_t *device,
+		struct system_counterval_t *system, void *ctx)
+{
+	struct snd_pcm_substream *substream = ctx;
+	struct azx_dev *azx_dev = get_azx_dev(substream);
+	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+	struct azx *chip = apcm->chip;
+	struct snd_pcm_runtime *runtime;
+	u64 ll_counter, ll_counter_l, ll_counter_h;
+	u64 tsc_counter, tsc_counter_l, tsc_counter_h;
+	u32 wallclk_ctr, wallclk_cycles;
+	bool direction;
+	u32 dma_select;
+	u32 timeout = 200;
+	u32 retry_count = 0;
+
+	runtime = substream->runtime;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		direction = 1;
+	else
+		direction = 0;
+
+	/* 0th stream tag is not used, so DMA ch 0 is for 1st stream tag */
+	do {
+		timeout = 100;
+		dma_select = (direction << GTSCC_CDMAS_DMA_DIR_SHIFT) |
+					(azx_dev->core.stream_tag - 1);
+		snd_hdac_chip_writel(azx_bus(chip), GTSCC, dma_select);
+
+		/* Enable the capture */
+		snd_hdac_chip_updatel(azx_bus(chip), GTSCC, 0, GTSCC_TSCCI_MASK);
+
+		while (timeout) {
+			if (snd_hdac_chip_readl(azx_bus(chip), GTSCC) &
+						GTSCC_TSCCD_MASK)
+				break;
+
+			timeout--;
+		}
+
+		if (!timeout) {
+			dev_err(chip->card->dev, "GTSCC capture Timedout!\n");
+			return -EIO;
+		}
+
+		/* Read wall clock counter */
+		wallclk_ctr = snd_hdac_chip_readl(azx_bus(chip), WALFCC);
+
+		/* Read TSC counter */
+		tsc_counter_l = snd_hdac_chip_readl(azx_bus(chip), TSCCL);
+		tsc_counter_h = snd_hdac_chip_readl(azx_bus(chip), TSCCU);
+
+		/* Read Link counter */
+		ll_counter_l = snd_hdac_chip_readl(azx_bus(chip), LLPCL);
+		ll_counter_h = snd_hdac_chip_readl(azx_bus(chip), LLPCU);
+
+		/* Ack: registers read done */
+		snd_hdac_chip_writel(azx_bus(chip), GTSCC, GTSCC_TSCCD_SHIFT);
+
+		tsc_counter = (tsc_counter_h << TSCCU_CCU_SHIFT) |
+						tsc_counter_l;
+
+		ll_counter = (ll_counter_h << LLPC_CCU_SHIFT) |	ll_counter_l;
+		wallclk_cycles = wallclk_ctr & WALFCC_CIF_MASK;
+
+		/*
+		 * An error occurs near frame "rollover". The clocks in
+		 * frame value indicates whether this error may have
+		 * occurred. Here we use the value of 10 i.e.,
+		 * HDA_MAX_CYCLE_OFFSET
+		 */
+		if (wallclk_cycles < HDA_MAX_CYCLE_VALUE - HDA_MAX_CYCLE_OFFSET
+					&& wallclk_cycles > HDA_MAX_CYCLE_OFFSET)
+			break;
+
+		/*
+		 * Sleep before we read again, else we may again get
+		 * value near to MAX_CYCLE. Try to sleep for different
+		 * amount of time so we dont hit the same number again
+		 */
+		udelay(retry_count++);
+
+	} while (retry_count != HDA_MAX_CYCLE_READ_RETRY);
+
+	if (retry_count == HDA_MAX_CYCLE_READ_RETRY) {
+		dev_err_ratelimited(chip->card->dev,
+			"Error in WALFCC cycle count\n");
+		return -EIO;
+	}
+
+	*device = ns_to_ktime(azx_scale64(ll_counter,
+				NSEC_PER_SEC, runtime->rate));
+	*device = ktime_add_ns(*device, (wallclk_cycles * NSEC_PER_SEC) /
+			       ((HDA_MAX_CYCLE_VALUE + 1) * runtime->rate));
+
+	*system = convert_art_to_tsc(tsc_counter);
+
+	return 0;
+}
+
+#else
+static int azx_get_sync_time(ktime_t *device,
+		struct system_counterval_t *system, void *ctx)
+{
+	return -ENXIO;
+}
+#endif
+
+static int azx_get_crosststamp(struct snd_pcm_substream *substream,
+			      struct system_device_crosststamp *xtstamp)
+{
+	return get_device_system_crosststamp(azx_get_sync_time,
+					substream, NULL, xtstamp);
+}
+
+static inline bool is_link_time_supported(struct snd_pcm_runtime *runtime,
+				struct snd_pcm_audio_tstamp_config *ts)
+{
+	if (runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME)
+		if (ts->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED)
+			return true;
+
+	return false;
+}
+
 static int azx_get_time_info(struct snd_pcm_substream *substream,
 			struct timespec *system_ts, struct timespec *audio_ts,
 			struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
 			struct snd_pcm_audio_tstamp_report *audio_tstamp_report)
 {
 	struct azx_dev *azx_dev = get_azx_dev(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct system_device_crosststamp xtstamp;
+	int ret;
 	u64 nsec;
 
 	if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) &&
@@ -361,8 +528,37 @@
 		audio_tstamp_report->accuracy_report = 1; /* rest of structure is valid */
 		audio_tstamp_report->accuracy = 42; /* 24 MHz WallClock == 42ns resolution */
 
-	} else
+	} else if (is_link_time_supported(runtime, audio_tstamp_config)) {
+
+		ret = azx_get_crosststamp(substream, &xtstamp);
+		if (ret)
+			return ret;
+
+		switch (runtime->tstamp_type) {
+		case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC:
+			return -EINVAL;
+
+		case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW:
+			*system_ts = ktime_to_timespec(xtstamp.sys_monoraw);
+			break;
+
+		default:
+			*system_ts = ktime_to_timespec(xtstamp.sys_realtime);
+			break;
+
+		}
+
+		*audio_ts = ktime_to_timespec(xtstamp.device);
+
+		audio_tstamp_report->actual_type =
+			SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED;
+		audio_tstamp_report->accuracy_report = 1;
+		/* 24 MHz WallClock == 42ns resolution */
+		audio_tstamp_report->accuracy = 42;
+
+	} else {
 		audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT;
+	}
 
 	return 0;
 }
@@ -412,6 +608,11 @@
 		goto unlock;
 	}
 	runtime->private_data = azx_dev;
+
+	if (chip->gts_present)
+		azx_pcm_hw.info = azx_pcm_hw.info |
+			SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME;
+
 	runtime->hw = azx_pcm_hw;
 	runtime->hw.channels_min = hinfo->channels_min;
 	runtime->hw.channels_max = hinfo->channels_max;
@@ -495,7 +696,7 @@
 	return snd_pcm_lib_default_mmap(substream, area);
 }
 
-static struct snd_pcm_ops azx_pcm_ops = {
+static const struct snd_pcm_ops azx_pcm_ops = {
 	.open = azx_pcm_open,
 	.close = azx_pcm_close,
 	.ioctl = snd_pcm_lib_ioctl,
diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h
index ec63bbf..a50e053 100644
--- a/sound/pci/hda/hda_controller.h
+++ b/sound/pci/hda/hda_controller.h
@@ -159,6 +159,9 @@
 	unsigned int region_requested:1;
 	unsigned int disabled:1; /* disabled by vga_switcheroo */
 
+	/* GTS present */
+	unsigned int gts_present:1;
+
 #ifdef CONFIG_SND_HDA_DSP_LOADER
 	struct azx_dev saved_azx_dev;
 #endif
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 160c7f7..c3469f7 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -54,6 +54,7 @@
 /* for snoop control */
 #include <asm/pgtable.h>
 #include <asm/cacheflush.h>
+#include <asm/cpufeature.h>
 #endif
 #include <sound/core.h>
 #include <sound/initval.h>
@@ -1663,6 +1664,22 @@
 		return -ENXIO;
 	}
 
+	if (IS_SKL_PLUS(pci))
+		snd_hdac_bus_parse_capabilities(bus);
+
+	/*
+	 * Some Intel CPUs has always running timer (ART) feature and
+	 * controller may have Global time sync reporting capability, so
+	 * check both of these before declaring synchronized time reporting
+	 * capability SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME
+	 */
+	chip->gts_present = false;
+
+#ifdef CONFIG_X86
+	if (bus->ppcap && boot_cpu_has(X86_FEATURE_ART))
+		chip->gts_present = true;
+#endif
+
 	if (chip->msi) {
 		if (chip->driver_caps & AZX_DCAPS_NO_MSI64) {
 			dev_dbg(card->dev, "Disabling 64bit MSI\n");
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 9ceb2bc..ad06866 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -4018,7 +4018,7 @@
 /*
  * PCM
  */
-static struct hda_pcm_stream ca0132_pcm_analog_playback = {
+static const struct hda_pcm_stream ca0132_pcm_analog_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 6,
@@ -4029,7 +4029,7 @@
 	},
 };
 
-static struct hda_pcm_stream ca0132_pcm_analog_capture = {
+static const struct hda_pcm_stream ca0132_pcm_analog_capture = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -4040,7 +4040,7 @@
 	},
 };
 
-static struct hda_pcm_stream ca0132_pcm_digital_playback = {
+static const struct hda_pcm_stream ca0132_pcm_digital_playback = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -4052,7 +4052,7 @@
 	},
 };
 
-static struct hda_pcm_stream ca0132_pcm_digital_capture = {
+static const struct hda_pcm_stream ca0132_pcm_digital_capture = {
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
@@ -4614,7 +4614,7 @@
 	kfree(codec->spec);
 }
 
-static struct hda_codec_ops ca0132_patch_ops = {
+static const struct hda_codec_ops ca0132_patch_ops = {
 	.build_controls = ca0132_build_controls,
 	.build_pcms = ca0132_build_pcms,
 	.init = ca0132_init,
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 56fefbd..ed62748 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -261,6 +261,7 @@
 	CXT_FIXUP_HP_530,
 	CXT_FIXUP_CAP_MIX_AMP_5047,
 	CXT_FIXUP_MUTE_LED_EAPD,
+	CXT_FIXUP_HP_SPECTRE,
 };
 
 /* for hda_fixup_thinkpad_acpi() */
@@ -765,6 +766,14 @@
 		.type = HDA_FIXUP_FUNC,
 		.v.func = cxt_fixup_mute_led_eapd,
 	},
+	[CXT_FIXUP_HP_SPECTRE] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			/* enable NID 0x1d for the speaker on top */
+			{ 0x1d, 0x91170111 },
+			{ }
+		}
+	},
 };
 
 static const struct snd_pci_quirk cxt5045_fixups[] = {
@@ -814,6 +823,7 @@
 	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(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
 	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),
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 575cefd..b58e8c7 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -5264,6 +5264,8 @@
 	[ALC269_FIXUP_THINKPAD_ACPI] = {
 		.type = HDA_FIXUP_FUNC,
 		.v.func = hda_fixup_thinkpad_acpi,
+		.chained = true,
+		.chain_id = ALC269_FIXUP_SKU_IGNORE,
 	},
 	[ALC269_FIXUP_DMIC_THINKPAD_ACPI] = {
 		.type = HDA_FIXUP_FUNC,
@@ -5806,6 +5808,13 @@
 	{0x14, 0x90170110}, \
 	{0x15, 0x0221401f}
 
+#define ALC295_STANDARD_PINS \
+	{0x12, 0xb7a60130}, \
+	{0x14, 0x90170110}, \
+	{0x17, 0x21014020}, \
+	{0x18, 0x21a19030}, \
+	{0x21, 0x04211020}
+
 #define ALC298_STANDARD_PINS \
 	{0x12, 0x90a60130}, \
 	{0x21, 0x03211020}
@@ -5846,6 +5855,10 @@
 		{0x14, 0x90170120},
 		{0x21, 0x02211030}),
 	SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+		{0x14, 0x90170110},
+		{0x1b, 0x02011020},
+		{0x21, 0x0221101f}),
+	SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
 		{0x14, 0x90170130},
 		{0x1b, 0x01014020},
 		{0x21, 0x0221103f}),
@@ -5911,6 +5924,10 @@
 		{0x14, 0x90170120},
 		{0x21, 0x02211030}),
 	SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+		{0x12, 0xb7a60130},
+		{0x14, 0x90170110},
+		{0x21, 0x02211020}),
+	SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
 		ALC256_STANDARD_PINS),
 	SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4,
 		{0x12, 0x90a60130},
@@ -6021,6 +6038,8 @@
 	SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
 		ALC292_STANDARD_PINS,
 		{0x13, 0x90a60140}),
+	SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+		ALC295_STANDARD_PINS),
 	SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
 		ALC298_STANDARD_PINS,
 		{0x17, 0x90170110}),
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index 8ae3bb7..b4aa4c1 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -847,7 +847,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_ice1712_playback_ops = {
+static const struct snd_pcm_ops snd_ice1712_playback_ops = {
 	.open =		snd_ice1712_playback_open,
 	.close =	snd_ice1712_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -858,7 +858,7 @@
 	.pointer =	snd_ice1712_playback_pointer,
 };
 
-static struct snd_pcm_ops snd_ice1712_playback_ds_ops = {
+static const struct snd_pcm_ops snd_ice1712_playback_ds_ops = {
 	.open =		snd_ice1712_playback_ds_open,
 	.close =	snd_ice1712_playback_ds_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -869,7 +869,7 @@
 	.pointer =	snd_ice1712_playback_ds_pointer,
 };
 
-static struct snd_pcm_ops snd_ice1712_capture_ops = {
+static const struct snd_pcm_ops snd_ice1712_capture_ops = {
 	.open =		snd_ice1712_capture_open,
 	.close =	snd_ice1712_capture_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1228,7 +1228,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_ice1712_playback_pro_ops = {
+static const struct snd_pcm_ops snd_ice1712_playback_pro_ops = {
 	.open =		snd_ice1712_playback_pro_open,
 	.close =	snd_ice1712_playback_pro_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1239,7 +1239,7 @@
 	.pointer =	snd_ice1712_playback_pro_pointer,
 };
 
-static struct snd_pcm_ops snd_ice1712_capture_pro_ops = {
+static const struct snd_pcm_ops snd_ice1712_capture_pro_ops = {
 	.open =		snd_ice1712_capture_pro_open,
 	.close =	snd_ice1712_capture_pro_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 0b22c00..e5c52ed 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -620,9 +620,7 @@
 
 static unsigned int stdclock_get_rate(struct snd_ice1712 *ice)
 {
-	unsigned int rate;
-	rate = stdclock_rate_list[inb(ICEMT1724(ice, RATE)) & 15];
-	return rate;
+	return stdclock_rate_list[inb(ICEMT1724(ice, RATE)) & 15];
 }
 
 static void stdclock_set_rate(struct snd_ice1712 *ice, unsigned int rate)
@@ -1113,7 +1111,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_vt1724_playback_pro_ops = {
+static const struct snd_pcm_ops snd_vt1724_playback_pro_ops = {
 	.open =		snd_vt1724_playback_pro_open,
 	.close =	snd_vt1724_playback_pro_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1124,7 +1122,7 @@
 	.pointer =	snd_vt1724_playback_pro_pointer,
 };
 
-static struct snd_pcm_ops snd_vt1724_capture_pro_ops = {
+static const struct snd_pcm_ops snd_vt1724_capture_pro_ops = {
 	.open =		snd_vt1724_capture_pro_open,
 	.close =	snd_vt1724_capture_pro_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1292,7 +1290,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_vt1724_playback_spdif_ops = {
+static const struct snd_pcm_ops snd_vt1724_playback_spdif_ops = {
 	.open =		snd_vt1724_playback_spdif_open,
 	.close =	snd_vt1724_playback_spdif_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1303,7 +1301,7 @@
 	.pointer =	snd_vt1724_pcm_pointer,
 };
 
-static struct snd_pcm_ops snd_vt1724_capture_spdif_ops = {
+static const struct snd_pcm_ops snd_vt1724_capture_spdif_ops = {
 	.open =		snd_vt1724_capture_spdif_open,
 	.close =	snd_vt1724_capture_spdif_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1437,7 +1435,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_vt1724_playback_indep_ops = {
+static const struct snd_pcm_ops snd_vt1724_playback_indep_ops = {
 	.open =		snd_vt1724_playback_indep_open,
 	.close =	snd_vt1724_playback_indep_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 9e1ad11..565f7f5 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -1681,7 +1681,7 @@
 	return snd_korg1212_copy_to(korg1212, dst, pos, count, 0, korg1212->channels * 2);
 }
 
-static struct snd_pcm_ops snd_korg1212_playback_ops = {
+static const struct snd_pcm_ops snd_korg1212_playback_ops = {
         .open =		snd_korg1212_playback_open,
         .close =	snd_korg1212_playback_close,
         .ioctl =	snd_korg1212_ioctl,
@@ -1693,7 +1693,7 @@
         .silence =	snd_korg1212_playback_silence,
 };
 
-static struct snd_pcm_ops snd_korg1212_capture_ops = {
+static const struct snd_pcm_ops snd_korg1212_capture_ops = {
 	.open =		snd_korg1212_capture_open,
 	.close =	snd_korg1212_capture_close,
 	.ioctl =	snd_korg1212_ioctl,
diff --git a/sound/pci/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c
index 3bd6985..1268ba3 100644
--- a/sound/pci/lola/lola_pcm.c
+++ b/sound/pci/lola/lola_pcm.c
@@ -586,7 +586,7 @@
 	}
 }
 
-static struct snd_pcm_ops lola_pcm_ops = {
+static const struct snd_pcm_ops lola_pcm_ops = {
 	.open = lola_pcm_open,
 	.close = lola_pcm_close,
 	.ioctl = snd_pcm_lib_ioctl,
diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c
index 8b8e2e5..c0f0c34 100644
--- a/sound/pci/lx6464es/lx6464es.c
+++ b/sound/pci/lx6464es/lx6464es.c
@@ -804,7 +804,7 @@
 	return err;
 }
 
-static struct snd_pcm_ops lx_ops_playback = {
+static const struct snd_pcm_ops lx_ops_playback = {
 	.open      = lx_pcm_open,
 	.close     = lx_pcm_close,
 	.ioctl     = snd_pcm_lib_ioctl,
@@ -815,7 +815,7 @@
 	.pointer   = lx_pcm_stream_pointer,
 };
 
-static struct snd_pcm_ops lx_ops_capture = {
+static const struct snd_pcm_ops lx_ops_capture = {
 	.open      = lx_pcm_open,
 	.close     = lx_pcm_close,
 	.ioctl     = snd_pcm_lib_ioctl,
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 17ae926..cafea6d 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -1834,7 +1834,7 @@
  * create pcm instance
  */
 
-static struct snd_pcm_ops snd_m3_playback_ops = {
+static const struct snd_pcm_ops snd_m3_playback_ops = {
 	.open =		snd_m3_playback_open,
 	.close =	snd_m3_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1845,7 +1845,7 @@
 	.pointer =	snd_m3_pcm_pointer,
 };
 
-static struct snd_pcm_ops snd_m3_capture_ops = {
+static const struct snd_pcm_ops snd_m3_capture_ops = {
 	.open =		snd_m3_capture_open,
 	.close =	snd_m3_capture_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index 25c0ddd..80d4399 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -922,7 +922,7 @@
 
 
 
-static struct snd_pcm_ops snd_mixart_playback_ops = {
+static const struct snd_pcm_ops snd_mixart_playback_ops = {
 	.open      = snd_mixart_playback_open,
 	.close     = snd_mixart_close,
 	.ioctl     = snd_pcm_lib_ioctl,
@@ -933,7 +933,7 @@
 	.pointer   = snd_mixart_stream_pointer,
 };
 
-static struct snd_pcm_ops snd_mixart_capture_ops = {
+static const struct snd_pcm_ops snd_mixart_capture_ops = {
 	.open      = snd_mixart_capture_open,
 	.close     = snd_mixart_close,
 	.ioctl     = snd_pcm_lib_ioctl,
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 4735e27..103fe31 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -902,7 +902,7 @@
 /*
  * create a pcm instance
  */
-static struct snd_pcm_ops snd_nm256_playback_ops = {
+static const struct snd_pcm_ops snd_nm256_playback_ops = {
 	.open =		snd_nm256_playback_open,
 	.close =	snd_nm256_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -917,7 +917,7 @@
 	.mmap =		snd_pcm_lib_mmap_iomem,
 };
 
-static struct snd_pcm_ops snd_nm256_capture_ops = {
+static const struct snd_pcm_ops snd_nm256_capture_ops = {
 	.open =		snd_nm256_capture_open,
 	.close =	snd_nm256_capture_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c
index aa2ebd1..042a243 100644
--- a/sound/pci/oxygen/oxygen_pcm.c
+++ b/sound/pci/oxygen/oxygen_pcm.c
@@ -631,7 +631,7 @@
 	return bytes_to_frames(runtime, curr_addr - (u32)runtime->dma_addr);
 }
 
-static struct snd_pcm_ops oxygen_rec_a_ops = {
+static const struct snd_pcm_ops oxygen_rec_a_ops = {
 	.open      = oxygen_rec_a_open,
 	.close     = oxygen_close,
 	.ioctl     = snd_pcm_lib_ioctl,
@@ -642,7 +642,7 @@
 	.pointer   = oxygen_pointer,
 };
 
-static struct snd_pcm_ops oxygen_rec_b_ops = {
+static const struct snd_pcm_ops oxygen_rec_b_ops = {
 	.open      = oxygen_rec_b_open,
 	.close     = oxygen_close,
 	.ioctl     = snd_pcm_lib_ioctl,
@@ -653,7 +653,7 @@
 	.pointer   = oxygen_pointer,
 };
 
-static struct snd_pcm_ops oxygen_rec_c_ops = {
+static const struct snd_pcm_ops oxygen_rec_c_ops = {
 	.open      = oxygen_rec_c_open,
 	.close     = oxygen_close,
 	.ioctl     = snd_pcm_lib_ioctl,
@@ -664,7 +664,7 @@
 	.pointer   = oxygen_pointer,
 };
 
-static struct snd_pcm_ops oxygen_spdif_ops = {
+static const struct snd_pcm_ops oxygen_spdif_ops = {
 	.open      = oxygen_spdif_open,
 	.close     = oxygen_close,
 	.ioctl     = snd_pcm_lib_ioctl,
@@ -675,7 +675,7 @@
 	.pointer   = oxygen_pointer,
 };
 
-static struct snd_pcm_ops oxygen_multich_ops = {
+static const struct snd_pcm_ops oxygen_multich_ops = {
 	.open      = oxygen_multich_open,
 	.close     = oxygen_close,
 	.ioctl     = snd_pcm_lib_ioctl,
@@ -686,7 +686,7 @@
 	.pointer   = oxygen_pointer,
 };
 
-static struct snd_pcm_ops oxygen_ac97_ops = {
+static const struct snd_pcm_ops oxygen_ac97_ops = {
 	.open      = oxygen_ac97_open,
 	.close     = oxygen_close,
 	.ioctl     = snd_pcm_lib_ioctl,
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index 9293235..bb7eee9 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -1146,7 +1146,7 @@
 }
 
 
-static struct snd_pcm_ops pcxhr_ops = {
+static const struct snd_pcm_ops pcxhr_ops = {
 	.open      = pcxhr_open,
 	.close     = pcxhr_close,
 	.ioctl     = snd_pcm_lib_ioctl,
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index 067a912..ada5f01 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -644,7 +644,7 @@
 	 .mono = lbus_play_mono3,
 	 },
 };
-static struct lbuspath lbus_rec_path = {
+static const struct lbuspath lbus_rec_path = {
 	.noconv = lbus_rec_noconv1,
 	.stereo = lbus_rec_stereo1,
 	.mono = lbus_rec_mono1,
@@ -1669,7 +1669,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_riptide_playback_ops = {
+static const struct snd_pcm_ops snd_riptide_playback_ops = {
 	.open = snd_riptide_playback_open,
 	.close = snd_riptide_playback_close,
 	.ioctl = snd_pcm_lib_ioctl,
@@ -1680,7 +1680,7 @@
 	.trigger = snd_riptide_trigger,
 	.pointer = snd_riptide_pointer,
 };
-static struct snd_pcm_ops snd_riptide_capture_ops = {
+static const struct snd_pcm_ops snd_riptide_capture_ops = {
 	.open = snd_riptide_capture_open,
 	.close = snd_riptide_capture_close,
 	.ioctl = snd_pcm_lib_ioctl,
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
index cd94ac5..96d15db 100644
--- a/sound/pci/rme32.c
+++ b/sound/pci/rme32.c
@@ -1196,7 +1196,7 @@
 }
 
 /* for halfduplex mode */
-static struct snd_pcm_ops snd_rme32_playback_spdif_ops = {
+static const struct snd_pcm_ops snd_rme32_playback_spdif_ops = {
 	.open =		snd_rme32_playback_spdif_open,
 	.close =	snd_rme32_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1210,7 +1210,7 @@
 	.mmap =		snd_pcm_lib_mmap_iomem,
 };
 
-static struct snd_pcm_ops snd_rme32_capture_spdif_ops = {
+static const struct snd_pcm_ops snd_rme32_capture_spdif_ops = {
 	.open =		snd_rme32_capture_spdif_open,
 	.close =	snd_rme32_capture_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1223,7 +1223,7 @@
 	.mmap =		snd_pcm_lib_mmap_iomem,
 };
 
-static struct snd_pcm_ops snd_rme32_playback_adat_ops = {
+static const struct snd_pcm_ops snd_rme32_playback_adat_ops = {
 	.open =		snd_rme32_playback_adat_open,
 	.close =	snd_rme32_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1236,7 +1236,7 @@
 	.mmap =		snd_pcm_lib_mmap_iomem,
 };
 
-static struct snd_pcm_ops snd_rme32_capture_adat_ops = {
+static const struct snd_pcm_ops snd_rme32_capture_adat_ops = {
 	.open =		snd_rme32_capture_adat_open,
 	.close =	snd_rme32_capture_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1249,7 +1249,7 @@
 };
 
 /* for fullduplex mode */
-static struct snd_pcm_ops snd_rme32_playback_spdif_fd_ops = {
+static const struct snd_pcm_ops snd_rme32_playback_spdif_fd_ops = {
 	.open =		snd_rme32_playback_spdif_open,
 	.close =	snd_rme32_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1261,7 +1261,7 @@
 	.ack =		snd_rme32_playback_fd_ack,
 };
 
-static struct snd_pcm_ops snd_rme32_capture_spdif_fd_ops = {
+static const struct snd_pcm_ops snd_rme32_capture_spdif_fd_ops = {
 	.open =		snd_rme32_capture_spdif_open,
 	.close =	snd_rme32_capture_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1273,7 +1273,7 @@
 	.ack =		snd_rme32_capture_fd_ack,
 };
 
-static struct snd_pcm_ops snd_rme32_playback_adat_fd_ops = {
+static const struct snd_pcm_ops snd_rme32_playback_adat_fd_ops = {
 	.open =		snd_rme32_playback_adat_open,
 	.close =	snd_rme32_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1284,7 +1284,7 @@
 	.ack =		snd_rme32_playback_fd_ack,
 };
 
-static struct snd_pcm_ops snd_rme32_capture_adat_fd_ops = {
+static const struct snd_pcm_ops snd_rme32_capture_adat_fd_ops = {
 	.open =		snd_rme32_capture_adat_open,
 	.close =	snd_rme32_capture_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index 41c31db..05b9da3 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -1505,7 +1505,7 @@
 	return snd_rme96_capture_ptr(rme96);
 }
 
-static struct snd_pcm_ops snd_rme96_playback_spdif_ops = {
+static const struct snd_pcm_ops snd_rme96_playback_spdif_ops = {
 	.open =		snd_rme96_playback_spdif_open,
 	.close =	snd_rme96_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1518,7 +1518,7 @@
 	.mmap =		snd_pcm_lib_mmap_iomem,
 };
 
-static struct snd_pcm_ops snd_rme96_capture_spdif_ops = {
+static const struct snd_pcm_ops snd_rme96_capture_spdif_ops = {
 	.open =		snd_rme96_capture_spdif_open,
 	.close =	snd_rme96_capture_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1530,7 +1530,7 @@
 	.mmap =		snd_pcm_lib_mmap_iomem,
 };
 
-static struct snd_pcm_ops snd_rme96_playback_adat_ops = {
+static const struct snd_pcm_ops snd_rme96_playback_adat_ops = {
 	.open =		snd_rme96_playback_adat_open,
 	.close =	snd_rme96_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1543,7 +1543,7 @@
 	.mmap =		snd_pcm_lib_mmap_iomem,
 };
 
-static struct snd_pcm_ops snd_rme96_capture_adat_ops = {
+static const struct snd_pcm_ops snd_rme96_capture_adat_ops = {
 	.open =		snd_rme96_capture_adat_open,
 	.close =	snd_rme96_capture_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 7c8941b..b94fc63 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -4861,7 +4861,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_hdsp_playback_ops = {
+static const struct snd_pcm_ops snd_hdsp_playback_ops = {
 	.open =		snd_hdsp_playback_open,
 	.close =	snd_hdsp_playback_release,
 	.ioctl =	snd_hdsp_ioctl,
@@ -4873,7 +4873,7 @@
 	.silence =	snd_hdsp_hw_silence,
 };
 
-static struct snd_pcm_ops snd_hdsp_capture_ops = {
+static const struct snd_pcm_ops snd_hdsp_capture_ops = {
 	.open =		snd_hdsp_capture_open,
 	.close =	snd_hdsp_capture_release,
 	.ioctl =	snd_hdsp_ioctl,
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index a4a999a..14bbf55 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -1666,7 +1666,7 @@
 			    HDSPM_AUTOSYNC_FROM_NONE) {
 
 				dev_warn(hdspm->card->dev,
-					 "Detected no Externel Sync\n");
+					 "Detected no External Sync\n");
 				not_set = 1;
 
 			} else if (rate != external_freq) {
@@ -6361,7 +6361,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_hdspm_ops = {
+static const struct snd_pcm_ops snd_hdspm_ops = {
 	.open = snd_hdspm_open,
 	.close = snd_hdspm_release,
 	.ioctl = snd_hdspm_ioctl,
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index fdbc0aa..55172c6 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -2368,7 +2368,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_rme9652_playback_ops = {
+static const struct snd_pcm_ops snd_rme9652_playback_ops = {
 	.open =		snd_rme9652_playback_open,
 	.close =	snd_rme9652_playback_release,
 	.ioctl =	snd_rme9652_ioctl,
@@ -2380,7 +2380,7 @@
 	.silence =	snd_rme9652_hw_silence,
 };
 
-static struct snd_pcm_ops snd_rme9652_capture_ops = {
+static const struct snd_pcm_ops snd_rme9652_capture_ops = {
 	.open =		snd_rme9652_capture_open,
 	.close =	snd_rme9652_capture_release,
 	.ioctl =	snd_rme9652_ioctl,
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index 1b6fad7..e1a1387 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -857,7 +857,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_sonicvibes_playback_ops = {
+static const struct snd_pcm_ops snd_sonicvibes_playback_ops = {
 	.open =		snd_sonicvibes_playback_open,
 	.close =	snd_sonicvibes_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -868,7 +868,7 @@
 	.pointer =	snd_sonicvibes_playback_pointer,
 };
 
-static struct snd_pcm_ops snd_sonicvibes_capture_ops = {
+static const struct snd_pcm_ops snd_sonicvibes_capture_ops = {
 	.open =		snd_sonicvibes_capture_open,
 	.close =	snd_sonicvibes_capture_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index 599d2b7..27f0ed8 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -2070,7 +2070,7 @@
    PCM operations
   ---------------------------------------------------------------------------*/
 
-static struct snd_pcm_ops snd_trident_playback_ops = {
+static const struct snd_pcm_ops snd_trident_playback_ops = {
 	.open =		snd_trident_playback_open,
 	.close =	snd_trident_playback_close,
 	.ioctl =	snd_trident_ioctl,
@@ -2081,7 +2081,7 @@
 	.pointer =	snd_trident_playback_pointer,
 };
 
-static struct snd_pcm_ops snd_trident_nx_playback_ops = {
+static const struct snd_pcm_ops snd_trident_nx_playback_ops = {
 	.open =		snd_trident_playback_open,
 	.close =	snd_trident_playback_close,
 	.ioctl =	snd_trident_ioctl,
@@ -2115,7 +2115,7 @@
 	.pointer =	snd_trident_playback_pointer,
 };
 
-static struct snd_pcm_ops snd_trident_foldback_ops = {
+static const struct snd_pcm_ops snd_trident_foldback_ops = {
 	.open =		snd_trident_foldback_open,
 	.close =	snd_trident_foldback_close,
 	.ioctl =	snd_trident_ioctl,
@@ -2126,7 +2126,7 @@
 	.pointer =	snd_trident_playback_pointer,
 };
 
-static struct snd_pcm_ops snd_trident_nx_foldback_ops = {
+static const struct snd_pcm_ops snd_trident_nx_foldback_ops = {
 	.open =		snd_trident_foldback_open,
 	.close =	snd_trident_foldback_close,
 	.ioctl =	snd_trident_ioctl,
@@ -2138,7 +2138,7 @@
 	.page =		snd_pcm_sgbuf_ops_page,
 };
 
-static struct snd_pcm_ops snd_trident_spdif_ops = {
+static const struct snd_pcm_ops snd_trident_spdif_ops = {
 	.open =		snd_trident_spdif_open,
 	.close =	snd_trident_spdif_close,
 	.ioctl =	snd_trident_ioctl,
@@ -2149,7 +2149,7 @@
 	.pointer =	snd_trident_spdif_pointer,
 };
 
-static struct snd_pcm_ops snd_trident_spdif_7018_ops = {
+static const struct snd_pcm_ops snd_trident_spdif_7018_ops = {
 	.open =		snd_trident_spdif_open,
 	.close =	snd_trident_spdif_close,
 	.ioctl =	snd_trident_ioctl,
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 3dd038b..38a17b4 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -1366,7 +1366,7 @@
 
 
 /* via686 playback callbacks */
-static struct snd_pcm_ops snd_via686_playback_ops = {
+static const struct snd_pcm_ops snd_via686_playback_ops = {
 	.open =		snd_via686_playback_open,
 	.close =	snd_via82xx_pcm_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1379,7 +1379,7 @@
 };
 
 /* via686 capture callbacks */
-static struct snd_pcm_ops snd_via686_capture_ops = {
+static const struct snd_pcm_ops snd_via686_capture_ops = {
 	.open =		snd_via82xx_capture_open,
 	.close =	snd_via82xx_pcm_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1392,7 +1392,7 @@
 };
 
 /* via823x DSX playback callbacks */
-static struct snd_pcm_ops snd_via8233_playback_ops = {
+static const struct snd_pcm_ops snd_via8233_playback_ops = {
 	.open =		snd_via8233_playback_open,
 	.close =	snd_via8233_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1405,7 +1405,7 @@
 };
 
 /* via823x multi-channel playback callbacks */
-static struct snd_pcm_ops snd_via8233_multi_ops = {
+static const struct snd_pcm_ops snd_via8233_multi_ops = {
 	.open =		snd_via8233_multi_open,
 	.close =	snd_via82xx_pcm_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -1418,7 +1418,7 @@
 };
 
 /* via823x capture callbacks */
-static struct snd_pcm_ops snd_via8233_capture_ops = {
+static const struct snd_pcm_ops snd_via8233_capture_ops = {
 	.open =		snd_via82xx_capture_open,
 	.close =	snd_via82xx_pcm_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index 99b9137..2f6d40f 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -804,7 +804,7 @@
 
 
 /* via686 playback callbacks */
-static struct snd_pcm_ops snd_via686_playback_ops = {
+static const struct snd_pcm_ops snd_via686_playback_ops = {
 	.open =		snd_via82xx_playback_open,
 	.close =	snd_via82xx_pcm_close,
 	.ioctl =	snd_pcm_lib_ioctl,
@@ -817,7 +817,7 @@
 };
 
 /* via686 capture callbacks */
-static struct snd_pcm_ops snd_via686_capture_ops = {
+static const struct snd_pcm_ops snd_via686_capture_ops = {
 	.open =		snd_via82xx_capture_open,
 	.close =	snd_via82xx_pcm_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index 4c26076..ffee284 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -1123,7 +1123,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_ymfpci_playback_ops = {
+static const struct snd_pcm_ops snd_ymfpci_playback_ops = {
 	.open =			snd_ymfpci_playback_open,
 	.close =		snd_ymfpci_playback_close,
 	.ioctl =		snd_pcm_lib_ioctl,
@@ -1134,7 +1134,7 @@
 	.pointer =		snd_ymfpci_playback_pointer,
 };
 
-static struct snd_pcm_ops snd_ymfpci_capture_rec_ops = {
+static const struct snd_pcm_ops snd_ymfpci_capture_rec_ops = {
 	.open =			snd_ymfpci_capture_rec_open,
 	.close =		snd_ymfpci_capture_close,
 	.ioctl =		snd_pcm_lib_ioctl,
@@ -1169,7 +1169,7 @@
 				     snd_pcm_std_chmaps, 2, 0, NULL);
 }
 
-static struct snd_pcm_ops snd_ymfpci_capture_ac97_ops = {
+static const struct snd_pcm_ops snd_ymfpci_capture_ac97_ops = {
 	.open =			snd_ymfpci_capture_ac97_open,
 	.close =		snd_ymfpci_capture_close,
 	.ioctl =		snd_pcm_lib_ioctl,
@@ -1203,7 +1203,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_ymfpci_playback_spdif_ops = {
+static const struct snd_pcm_ops snd_ymfpci_playback_spdif_ops = {
 	.open =			snd_ymfpci_playback_spdif_open,
 	.close =		snd_ymfpci_playback_spdif_close,
 	.ioctl =		snd_pcm_lib_ioctl,
@@ -1236,7 +1236,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_ymfpci_playback_4ch_ops = {
+static const struct snd_pcm_ops snd_ymfpci_playback_4ch_ops = {
 	.open =			snd_ymfpci_playback_4ch_open,
 	.close =		snd_ymfpci_playback_4ch_close,
 	.ioctl =		snd_pcm_lib_ioctl,
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c
index 3682425..b84d7d3 100644
--- a/sound/ppc/snd_ps3.c
+++ b/sound/ppc/snd_ps3.c
@@ -564,9 +564,7 @@
 
 static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream)
 {
-	int ret;
-	ret = snd_pcm_lib_free_pages(substream);
-	return ret;
+	return snd_pcm_lib_free_pages(substream);
 };
 
 static int snd_ps3_delay_to_bytes(struct snd_pcm_substream *substream,
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
index d1fb035..504c7cd 100644
--- a/sound/soc/amd/acp-pcm-dma.c
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -897,7 +897,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops acp_dma_ops = {
+static const struct snd_pcm_ops acp_dma_ops = {
 	.open = acp_dma_open,
 	.close = acp_dma_close,
 	.ioctl = snd_pcm_lib_ioctl,
diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c
index 6d9b8b4..89ac5f5 100644
--- a/sound/soc/atmel/atmel-classd.c
+++ b/sound/soc/atmel/atmel-classd.c
@@ -308,9 +308,11 @@
 
 static struct snd_soc_codec_driver soc_codec_dev_classd = {
 	.probe		= atmel_classd_codec_probe,
-	.controls	= atmel_classd_snd_controls,
-	.num_controls	= ARRAY_SIZE(atmel_classd_snd_controls),
 	.get_regmap	= atmel_classd_codec_get_remap,
+	.component_driver = {
+		.controls		= atmel_classd_snd_controls,
+		.num_controls		= ARRAY_SIZE(atmel_classd_snd_controls),
+	},
 };
 
 /* codec dai component */
diff --git a/sound/soc/atmel/atmel-pcm-pdc.c b/sound/soc/atmel/atmel-pcm-pdc.c
index da861b4..91b7069 100644
--- a/sound/soc/atmel/atmel-pcm-pdc.c
+++ b/sound/soc/atmel/atmel-pcm-pdc.c
@@ -381,7 +381,7 @@
 	return 0;
 }
 
-static struct snd_pcm_ops atmel_pcm_ops = {
+static const struct snd_pcm_ops atmel_pcm_ops = {
 	.open		= atmel_pcm_open,
 	.close		= atmel_pcm_close,
 	.ioctl		= snd_pcm_lib_ioctl,
diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c
index 5f56da6..c917df7 100644
--- a/sound/soc/atmel/atmel-pdmic.c
+++ b/sound/soc/atmel/atmel-pdmic.c
@@ -80,7 +80,7 @@
 
 	if (pdata->mic_max_freq < pdata->mic_min_freq) {
 		dev_err(dev,
-			"mic-max-freq should not less than mic-min-freq\n");
+			"mic-max-freq should not be less than mic-min-freq\n");
 		return ERR_PTR(-EINVAL);
 	}
 
@@ -115,8 +115,10 @@
 		return ret;
 
 	ret =  clk_prepare_enable(dd->pclk);
-	if (ret)
+	if (ret) {
+		clk_disable_unprepare(dd->gclk);
 		return ret;
+	}
 
 	/* Clear all bits in the Control Register(PDMIC_CR) */
 	regmap_write(dd->regmap, PDMIC_CR, 0);
@@ -283,7 +285,7 @@
 	8, ARRAY_SIZE(mic_gain_table)-1, TLV_DB_SCALE_ITEM(-6500, 100, 0),
 );
 
-int pdmic_get_mic_volsw(struct snd_kcontrol *kcontrol,
+static int pdmic_get_mic_volsw(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
@@ -357,8 +359,10 @@
 
 static struct snd_soc_codec_driver soc_codec_dev_pdmic = {
 	.probe		= atmel_pdmic_codec_probe,
-	.controls	= atmel_pdmic_snd_controls,
-	.num_controls	= ARRAY_SIZE(atmel_pdmic_snd_controls),
+	.component_driver = {
+		.controls		= atmel_pdmic_snd_controls,
+		.num_controls		= ARRAY_SIZE(atmel_pdmic_snd_controls),
+	},
 };
 
 /* codec dai component */
@@ -596,7 +600,7 @@
 	dd->irq = platform_get_irq(pdev, 0);
 	if (dd->irq < 0) {
 		ret = dd->irq;
-		dev_err(dev, "failed to could not get irq: %d\n", ret);
+		dev_err(dev, "failed to get irq: %d\n", ret);
 		return ret;
 	}
 
@@ -614,7 +618,7 @@
 		return ret;
 	}
 
-	/* The gclk clock frequency must always be tree times
+	/* The gclk clock frequency must always be three times
 	 * lower than the pclk clock frequency
 	 */
 	ret = clk_set_rate(dd->gclk, clk_get_rate(dd->pclk)/3);
@@ -649,7 +653,7 @@
 		return ret;
 	}
 
-	/* Get the minimal and maximal sample rate that micphone supports */
+	/* Get the minimal and maximal sample rate that the microphone supports */
 	atmel_pdmic_get_sample_rate(dd, &rate_min, &rate_max);
 
 	/* register cpu dai */
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
index e8bed6b..b013a4c 100644
--- a/sound/soc/codecs/88pm860x-codec.c
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -1361,12 +1361,14 @@
 	.set_bias_level	= pm860x_set_bias_level,
 	.get_regmap	= pm860x_get_regmap,
 
-	.controls = pm860x_snd_controls,
-	.num_controls = ARRAY_SIZE(pm860x_snd_controls),
-	.dapm_widgets = pm860x_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(pm860x_dapm_widgets),
-	.dapm_routes = pm860x_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(pm860x_dapm_routes),
+	.component_driver = {
+		.controls		= pm860x_snd_controls,
+		.num_controls		= ARRAY_SIZE(pm860x_snd_controls),
+		.dapm_widgets		= pm860x_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(pm860x_dapm_widgets),
+		.dapm_routes		= pm860x_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(pm860x_dapm_routes),
+	},
 };
 
 static int pm860x_codec_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 1cd6ab3..c67667b 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -92,6 +92,7 @@
 	select SND_SOC_MAX9877 if I2C
 	select SND_SOC_MC13783 if MFD_MC13XXX
 	select SND_SOC_ML26124 if I2C
+	select SND_SOC_NAU8810 if I2C
 	select SND_SOC_NAU8825 if I2C
 	select SND_SOC_HDMI_CODEC
 	select SND_SOC_PCM1681 if I2C
@@ -112,6 +113,8 @@
 	select SND_SOC_RT5645 if I2C
 	select SND_SOC_RT5651 if I2C
 	select SND_SOC_RT5659 if I2C
+	select SND_SOC_RT5660 if I2C
+	select SND_SOC_RT5663 if I2C
 	select SND_SOC_RT5670 if I2C
 	select SND_SOC_RT5677 if I2C && SPI_MASTER
 	select SND_SOC_SGTL5000 if I2C
@@ -645,6 +648,8 @@
 	default y if SND_SOC_RT5645=y
 	default y if SND_SOC_RT5651=y
 	default y if SND_SOC_RT5659=y
+	default y if SND_SOC_RT5660=y
+	default y if SND_SOC_RT5663=y
 	default y if SND_SOC_RT5670=y
 	default y if SND_SOC_RT5677=y
 	default m if SND_SOC_RT5514=m
@@ -653,6 +658,8 @@
 	default m if SND_SOC_RT5645=m
 	default m if SND_SOC_RT5651=m
 	default m if SND_SOC_RT5659=m
+	default m if SND_SOC_RT5660=m
+	default m if SND_SOC_RT5663=m
 	default m if SND_SOC_RT5670=m
 	default m if SND_SOC_RT5677=m
 
@@ -665,6 +672,7 @@
 
 config SND_SOC_RT286
 	tristate
+	select SND_SOC_RT5663
 	depends on I2C
 
 config SND_SOC_RT298
@@ -697,6 +705,12 @@
 config SND_SOC_RT5659
 	tristate
 
+config SND_SOC_RT5660
+	tristate
+
+config SND_SOC_RT5663
+	tristate
+
 config SND_SOC_RT5670
 	tristate
 
@@ -1064,6 +1078,10 @@
 config SND_SOC_ML26124
 	tristate
 
+config SND_SOC_NAU8810
+	tristate "Nuvoton Technology Corporation NAU88C10 CODEC"
+	depends on I2C
+
 config SND_SOC_NAU8825
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 58036af..958cd49 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -86,6 +86,7 @@
 snd-soc-max9860-objs := max9860.o
 snd-soc-mc13783-objs := mc13783.o
 snd-soc-ml26124-objs := ml26124.o
+snd-soc-nau8810-objs := nau8810.o
 snd-soc-nau8825-objs := nau8825.o
 snd-soc-hdmi-codec-objs := hdmi-codec.o
 snd-soc-pcm1681-objs := pcm1681.o
@@ -112,6 +113,8 @@
 snd-soc-rt5645-objs := rt5645.o
 snd-soc-rt5651-objs := rt5651.o
 snd-soc-rt5659-objs := rt5659.o
+snd-soc-rt5660-objs := rt5660.o
+snd-soc-rt5663-objs := rt5663.o
 snd-soc-rt5670-objs := rt5670.o
 snd-soc-rt5677-objs := rt5677.o
 snd-soc-rt5677-spi-objs := rt5677-spi.o
@@ -307,6 +310,7 @@
 obj-$(CONFIG_SND_SOC_MAX9860)	+= snd-soc-max9860.o
 obj-$(CONFIG_SND_SOC_MC13783)	+= snd-soc-mc13783.o
 obj-$(CONFIG_SND_SOC_ML26124)	+= snd-soc-ml26124.o
+obj-$(CONFIG_SND_SOC_NAU8810)   += snd-soc-nau8810.o
 obj-$(CONFIG_SND_SOC_NAU8825)   += snd-soc-nau8825.o
 obj-$(CONFIG_SND_SOC_HDMI_CODEC)	+= snd-soc-hdmi-codec.o
 obj-$(CONFIG_SND_SOC_PCM1681)	+= snd-soc-pcm1681.o
@@ -333,6 +337,8 @@
 obj-$(CONFIG_SND_SOC_RT5645)	+= snd-soc-rt5645.o
 obj-$(CONFIG_SND_SOC_RT5651)	+= snd-soc-rt5651.o
 obj-$(CONFIG_SND_SOC_RT5659)	+= snd-soc-rt5659.o
+obj-$(CONFIG_SND_SOC_RT5660)	+= snd-soc-rt5660.o
+obj-$(CONFIG_SND_SOC_RT5663)	+= snd-soc-rt5663.o
 obj-$(CONFIG_SND_SOC_RT5670)	+= snd-soc-rt5670.o
 obj-$(CONFIG_SND_SOC_RT5677)	+= snd-soc-rt5677.o
 obj-$(CONFIG_SND_SOC_RT5677_SPI)	+= snd-soc-rt5677-spi.o
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index 2fc8915..935ff7c 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -2408,28 +2408,28 @@
 {
 	u32 value;
 
-	if (of_get_property(np, "stericsson,amic1-type-single-ended", NULL))
+	if (of_property_read_bool(np, "stericsson,amic1-type-single-ended"))
 		codec->amics.mic1_type = AMIC_TYPE_SINGLE_ENDED;
 	else
 		codec->amics.mic1_type = AMIC_TYPE_DIFFERENTIAL;
 
-	if (of_get_property(np, "stericsson,amic2-type-single-ended", NULL))
+	if (of_property_read_bool(np, "stericsson,amic2-type-single-ended"))
 		codec->amics.mic2_type = AMIC_TYPE_SINGLE_ENDED;
 	else
 		codec->amics.mic2_type = AMIC_TYPE_DIFFERENTIAL;
 
 	/* Has a non-standard Vamic been requested? */
-	if (of_get_property(np, "stericsson,amic1a-bias-vamic2", NULL))
+	if (of_property_read_bool(np, "stericsson,amic1a-bias-vamic2"))
 		codec->amics.mic1a_micbias = AMIC_MICBIAS_VAMIC2;
 	else
 		codec->amics.mic1a_micbias = AMIC_MICBIAS_VAMIC1;
 
-	if (of_get_property(np, "stericsson,amic1b-bias-vamic2", NULL))
+	if (of_property_read_bool(np, "stericsson,amic1b-bias-vamic2"))
 		codec->amics.mic1b_micbias = AMIC_MICBIAS_VAMIC2;
 	else
 		codec->amics.mic1b_micbias = AMIC_MICBIAS_VAMIC1;
 
-	if (of_get_property(np, "stericsson,amic2-bias-vamic1", NULL))
+	if (of_property_read_bool(np, "stericsson,amic2-bias-vamic1"))
 		codec->amics.mic2_micbias = AMIC_MICBIAS_VAMIC1;
 	else
 		codec->amics.mic2_micbias = AMIC_MICBIAS_VAMIC2;
@@ -2525,12 +2525,14 @@
 
 static struct snd_soc_codec_driver ab8500_codec_driver = {
 	.probe =		ab8500_codec_probe,
-	.controls =		ab8500_ctrls,
-	.num_controls =		ARRAY_SIZE(ab8500_ctrls),
-	.dapm_widgets =		ab8500_dapm_widgets,
-	.num_dapm_widgets =	ARRAY_SIZE(ab8500_dapm_widgets),
-	.dapm_routes =		ab8500_dapm_routes,
-	.num_dapm_routes =	ARRAY_SIZE(ab8500_dapm_routes),
+	.component_driver = {
+		.controls =		ab8500_ctrls,
+		.num_controls =		ARRAY_SIZE(ab8500_ctrls),
+		.dapm_widgets =		ab8500_dapm_widgets,
+		.num_dapm_widgets =	ARRAY_SIZE(ab8500_dapm_widgets),
+		.dapm_routes =		ab8500_dapm_routes,
+		.num_dapm_routes =	ARRAY_SIZE(ab8500_dapm_routes),
+	},
 };
 
 static int ab8500_codec_driver_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index 5b3224c..f7f04c6 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -117,10 +117,12 @@
 	.suspend =	ac97_soc_suspend,
 	.resume =	ac97_soc_resume,
 
-	.dapm_widgets = ac97_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ac97_widgets),
-	.dapm_routes = ac97_routes,
-	.num_dapm_routes = ARRAY_SIZE(ac97_routes),
+	.component_driver = {
+		.dapm_widgets		= ac97_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ac97_widgets),
+		.dapm_routes		= ac97_routes,
+		.num_dapm_routes	= ARRAY_SIZE(ac97_routes),
+	},
 };
 
 static int ac97_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index e2ce6c4..a478239 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -327,12 +327,14 @@
 	.suspend = ad1836_suspend,
 	.resume = ad1836_resume,
 
-	.controls = ad183x_controls,
-	.num_controls = ARRAY_SIZE(ad183x_controls),
-	.dapm_widgets = ad183x_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ad183x_dapm_widgets),
-	.dapm_routes = ad183x_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(ad183x_dapm_routes),
+	.component_driver = {
+		.controls		= ad183x_controls,
+		.num_controls		= ARRAY_SIZE(ad183x_controls),
+		.dapm_widgets		= ad183x_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ad183x_dapm_widgets),
+		.dapm_routes		= ad183x_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(ad183x_dapm_routes),
+	},
 };
 
 static const struct reg_default ad1836_reg_defaults[] = {
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index 3a3f3f2..d643557 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -410,12 +410,14 @@
 
 static struct snd_soc_codec_driver soc_codec_dev_ad193x = {
 	.probe = ad193x_codec_probe,
-	.controls = ad193x_snd_controls,
-	.num_controls = ARRAY_SIZE(ad193x_snd_controls),
-	.dapm_widgets = ad193x_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ad193x_dapm_widgets),
-	.dapm_routes = audio_paths,
-	.num_dapm_routes = ARRAY_SIZE(audio_paths),
+	.component_driver = {
+		.controls		= ad193x_snd_controls,
+		.num_controls		= ARRAY_SIZE(ad193x_snd_controls),
+		.dapm_widgets		= ad193x_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ad193x_dapm_widgets),
+		.dapm_routes		= audio_paths,
+		.num_dapm_routes	= ARRAY_SIZE(audio_paths),
+	},
 };
 
 const struct regmap_config ad193x_regmap_config = {
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index 9ef20db..b7c1b9f 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -299,12 +299,14 @@
 	.probe = 	ad1980_soc_probe,
 	.remove = 	ad1980_soc_remove,
 
-	.controls = ad1980_snd_ac97_controls,
-	.num_controls = ARRAY_SIZE(ad1980_snd_ac97_controls),
-	.dapm_widgets = ad1980_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ad1980_dapm_widgets),
-	.dapm_routes = ad1980_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(ad1980_dapm_routes),
+	.component_driver = {
+		.controls		= ad1980_snd_ac97_controls,
+		.num_controls		= ARRAY_SIZE(ad1980_snd_ac97_controls),
+		.dapm_widgets		= ad1980_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ad1980_dapm_widgets),
+		.dapm_routes		= ad1980_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(ad1980_dapm_routes),
+	},
 };
 
 static int ad1980_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c
index a9400ae..3e358a4 100644
--- a/sound/soc/codecs/ad73311.c
+++ b/sound/soc/codecs/ad73311.c
@@ -55,10 +55,12 @@
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_ad73311 = {
-	.dapm_widgets = ad73311_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ad73311_dapm_widgets),
-	.dapm_routes = ad73311_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(ad73311_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= ad73311_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ad73311_dapm_widgets),
+		.dapm_routes		= ad73311_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(ad73311_dapm_routes),
+	},
 };
 
 static int ad73311_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index 1556b36..8fa9045 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -1466,12 +1466,14 @@
 
 	.set_pll = adau1373_set_pll,
 
-	.controls = adau1373_controls,
-	.num_controls = ARRAY_SIZE(adau1373_controls),
-	.dapm_widgets = adau1373_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(adau1373_dapm_widgets),
-	.dapm_routes = adau1373_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(adau1373_dapm_routes),
+	.component_driver = {
+		.controls		= adau1373_controls,
+		.num_controls		= ARRAY_SIZE(adau1373_controls),
+		.dapm_widgets		= adau1373_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(adau1373_dapm_widgets),
+		.dapm_routes		= adau1373_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(adau1373_dapm_routes),
+	},
 };
 
 static int adau1373_i2c_probe(struct i2c_client *client,
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index de53c0d..3bad1bc 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -765,13 +765,14 @@
 	.set_bias_level		= adau1701_set_bias_level,
 	.idle_bias_off		= true,
 
-	.controls		= adau1701_controls,
-	.num_controls		= ARRAY_SIZE(adau1701_controls),
-	.dapm_widgets		= adau1701_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(adau1701_dapm_widgets),
-	.dapm_routes		= adau1701_dapm_routes,
-	.num_dapm_routes	= ARRAY_SIZE(adau1701_dapm_routes),
-
+	.component_driver = {
+		.controls		= adau1701_controls,
+		.num_controls		= ARRAY_SIZE(adau1701_controls),
+		.dapm_widgets		= adau1701_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(adau1701_dapm_widgets),
+		.dapm_routes		= adau1701_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(adau1701_dapm_routes),
+	},
 	.set_sysclk		= adau1701_set_sysclk,
 };
 
diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c
index b95d29d..3bc3cc5 100644
--- a/sound/soc/codecs/adau1761.c
+++ b/sound/soc/codecs/adau1761.c
@@ -719,12 +719,14 @@
 	.set_bias_level	= adau1761_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = adau1761_controls,
-	.num_controls = ARRAY_SIZE(adau1761_controls),
-	.dapm_widgets = adau1x61_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(adau1x61_dapm_widgets),
-	.dapm_routes = adau1x61_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(adau1x61_dapm_routes),
+	.component_driver = {
+		.controls		= adau1761_controls,
+		.num_controls		= ARRAY_SIZE(adau1761_controls),
+		.dapm_widgets		= adau1x61_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(adau1x61_dapm_widgets),
+		.dapm_routes		= adau1x61_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(adau1x61_dapm_routes),
+	},
 };
 
 #define ADAU1761_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c
index bc1bb56..546071c 100644
--- a/sound/soc/codecs/adau1781.c
+++ b/sound/soc/codecs/adau1781.c
@@ -432,12 +432,14 @@
 	.set_bias_level = adau1781_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = adau1781_controls,
-	.num_controls = ARRAY_SIZE(adau1781_controls),
-	.dapm_widgets = adau1781_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(adau1781_dapm_widgets),
-	.dapm_routes = adau1781_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(adau1781_dapm_routes),
+	.component_driver = {
+		.controls		= adau1781_controls,
+		.num_controls		= ARRAY_SIZE(adau1781_controls),
+		.dapm_widgets		= adau1781_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(adau1781_dapm_widgets),
+		.dapm_routes		= adau1781_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(adau1781_dapm_routes),
+	},
 };
 
 #define ADAU1781_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c
index 9bdd15f..b319db6 100644
--- a/sound/soc/codecs/adau1977.c
+++ b/sound/soc/codecs/adau1977.c
@@ -873,12 +873,14 @@
 	.set_sysclk = adau1977_set_sysclk,
 	.idle_bias_off = true,
 
-	.controls = adau1977_snd_controls,
-	.num_controls = ARRAY_SIZE(adau1977_snd_controls),
-	.dapm_widgets = adau1977_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(adau1977_dapm_widgets),
-	.dapm_routes = adau1977_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(adau1977_dapm_routes),
+	.component_driver = {
+		.controls		= adau1977_snd_controls,
+		.num_controls		= ARRAY_SIZE(adau1977_snd_controls),
+		.dapm_widgets		= adau1977_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(adau1977_dapm_widgets),
+		.dapm_routes		= adau1977_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(adau1977_dapm_routes),
+	},
 };
 
 static int adau1977_setup_micbias(struct adau1977 *adau1977)
diff --git a/sound/soc/codecs/adau7002.c b/sound/soc/codecs/adau7002.c
index 9df72c6..6384c54 100644
--- a/sound/soc/codecs/adau7002.c
+++ b/sound/soc/codecs/adau7002.c
@@ -39,10 +39,12 @@
 };
 
 static const struct snd_soc_codec_driver adau7002_codec_driver = {
-	.dapm_widgets = adau7002_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(adau7002_widgets),
-	.dapm_routes = adau7002_routes,
-	.num_dapm_routes = ARRAY_SIZE(adau7002_routes),
+	.component_driver = {
+		.dapm_widgets		= adau7002_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(adau7002_widgets),
+		.dapm_routes		= adau7002_routes,
+		.num_dapm_routes	= ARRAY_SIZE(adau7002_routes),
+	},
 };
 
 static int adau7002_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index acff8d6..6e793eb 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -834,12 +834,14 @@
 	.set_pll = adav80x_set_pll,
 	.set_sysclk = adav80x_set_sysclk,
 
-	.controls = adav80x_controls,
-	.num_controls = ARRAY_SIZE(adav80x_controls),
-	.dapm_widgets = adav80x_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(adav80x_dapm_widgets),
-	.dapm_routes = adav80x_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes),
+	.component_driver = {
+		.controls		= adav80x_controls,
+		.num_controls		= ARRAY_SIZE(adav80x_controls),
+		.dapm_widgets		= adav80x_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(adav80x_dapm_widgets),
+		.dapm_routes		= adav80x_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(adav80x_dapm_routes),
+	},
 };
 
 int adav80x_bus_probe(struct device *dev, struct regmap *regmap)
diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c
index c5be1bd..90c756d 100644
--- a/sound/soc/codecs/ads117x.c
+++ b/sound/soc/codecs/ads117x.c
@@ -59,10 +59,12 @@
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_ads117x = {
-	.dapm_widgets = ads117x_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ads117x_dapm_widgets),
-	.dapm_routes = ads117x_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(ads117x_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= ads117x_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ads117x_dapm_widgets),
+		.dapm_routes		= ads117x_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(ads117x_dapm_routes),
+	},
 };
 
 static int ads117x_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index 595d02d..1a9d233 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -163,7 +163,10 @@
 		.stream_name = "Playback",
 		.channels_min = 2,
 		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_8000_192000,
+		.rates = SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+			 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+			 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+			 SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE  |
 			   SNDRV_PCM_FMTBIT_S24_3LE |
 			   SNDRV_PCM_FMTBIT_S24_LE
@@ -245,10 +248,12 @@
 	.suspend = ak4104_soc_suspend,
 	.resume = ak4104_soc_resume,
 
-	.dapm_widgets = ak4104_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ak4104_dapm_widgets),
-	.dapm_routes = ak4104_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(ak4104_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= ak4104_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ak4104_dapm_widgets),
+		.dapm_routes		= ak4104_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(ak4104_dapm_routes),
+	}
 };
 
 static const struct regmap_config ak4104_regmap = {
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 54428c6..66cfffd 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -395,12 +395,14 @@
 	.set_bias_level = ak4535_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = ak4535_snd_controls,
-	.num_controls = ARRAY_SIZE(ak4535_snd_controls),
-	.dapm_widgets = ak4535_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets),
-	.dapm_routes = ak4535_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(ak4535_audio_map),
+	.component_driver = {
+		.controls		= ak4535_snd_controls,
+		.num_controls		= ARRAY_SIZE(ak4535_snd_controls),
+		.dapm_widgets		= ak4535_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ak4535_dapm_widgets),
+		.dapm_routes		= ak4535_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(ak4535_audio_map),
+	},
 };
 
 static int ak4535_i2c_probe(struct i2c_client *i2c,
diff --git a/sound/soc/codecs/ak4554.c b/sound/soc/codecs/ak4554.c
index 298dedc..b92c548 100644
--- a/sound/soc/codecs/ak4554.c
+++ b/sound/soc/codecs/ak4554.c
@@ -65,10 +65,12 @@
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_ak4554 = {
-	.dapm_widgets = ak4554_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ak4554_dapm_widgets),
-	.dapm_routes = ak4554_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(ak4554_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= ak4554_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ak4554_dapm_widgets),
+		.dapm_routes		= ak4554_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(ak4554_dapm_routes),
+	},
 };
 
 static int ak4554_soc_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
index 97798d2..e819dd8 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -458,12 +458,14 @@
 	.suspend		= ak4613_suspend,
 	.resume			= ak4613_resume,
 	.set_bias_level		= ak4613_set_bias_level,
-	.controls		= ak4613_snd_controls,
-	.num_controls		= ARRAY_SIZE(ak4613_snd_controls),
-	.dapm_widgets		= ak4613_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(ak4613_dapm_widgets),
-	.dapm_routes		= ak4613_intercon,
-	.num_dapm_routes	= ARRAY_SIZE(ak4613_intercon),
+	.component_driver = {
+		.controls		= ak4613_snd_controls,
+		.num_controls		= ARRAY_SIZE(ak4613_snd_controls),
+		.dapm_widgets		= ak4613_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ak4613_dapm_widgets),
+		.dapm_routes		= ak4613_intercon,
+		.num_dapm_routes	= ARRAY_SIZE(ak4613_intercon),
+	},
 };
 
 static void ak4613_parse_of(struct ak4613_priv *priv,
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
index b14176f..c91717d 100644
--- a/sound/soc/codecs/ak4641.c
+++ b/sound/soc/codecs/ak4641.c
@@ -505,12 +505,14 @@
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
-	.controls		= ak4641_snd_controls,
-	.num_controls		= ARRAY_SIZE(ak4641_snd_controls),
-	.dapm_widgets		= ak4641_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(ak4641_dapm_widgets),
-	.dapm_routes		= ak4641_audio_map,
-	.num_dapm_routes	= ARRAY_SIZE(ak4641_audio_map),
+	.component_driver = {
+		.controls		= ak4641_snd_controls,
+		.num_controls		= ARRAY_SIZE(ak4641_snd_controls),
+		.dapm_widgets		= ak4641_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ak4641_dapm_widgets),
+		.dapm_routes		= ak4641_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(ak4641_audio_map),
+	},
 	.set_bias_level		= ak4641_set_bias_level,
 	.suspend_bias_off	= true,
 };
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index cc941d6..2609f95 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -555,12 +555,14 @@
 	.suspend		= ak4642_suspend,
 	.resume			= ak4642_resume,
 	.set_bias_level		= ak4642_set_bias_level,
-	.controls		= ak4642_snd_controls,
-	.num_controls		= ARRAY_SIZE(ak4642_snd_controls),
-	.dapm_widgets		= ak4642_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(ak4642_dapm_widgets),
-	.dapm_routes		= ak4642_intercon,
-	.num_dapm_routes	= ARRAY_SIZE(ak4642_intercon),
+	.component_driver = {
+		.controls		= ak4642_snd_controls,
+		.num_controls		= ARRAY_SIZE(ak4642_snd_controls),
+		.dapm_widgets		= ak4642_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ak4642_dapm_widgets),
+		.dapm_routes		= ak4642_intercon,
+		.num_dapm_routes	= ARRAY_SIZE(ak4642_intercon),
+	},
 };
 
 static const struct regmap_config ak4642_regmap = {
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
index c73a9f6..6088afa 100644
--- a/sound/soc/codecs/ak4671.c
+++ b/sound/soc/codecs/ak4671.c
@@ -612,12 +612,14 @@
 
 static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
 	.set_bias_level = ak4671_set_bias_level,
-	.controls = ak4671_snd_controls,
-	.num_controls = ARRAY_SIZE(ak4671_snd_controls),
-	.dapm_widgets = ak4671_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ak4671_dapm_widgets),
-	.dapm_routes = ak4671_intercon,
-	.num_dapm_routes = ARRAY_SIZE(ak4671_intercon),
+	.component_driver = {
+		.controls		= ak4671_snd_controls,
+		.num_controls		= ARRAY_SIZE(ak4671_snd_controls),
+		.dapm_widgets		= ak4671_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ak4671_dapm_widgets),
+		.dapm_routes		= ak4671_intercon,
+		.num_dapm_routes	= ARRAY_SIZE(ak4671_intercon),
+	},
 };
 
 static const struct regmap_config ak4671_regmap = {
diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c
index afa9536..0ef2df2 100644
--- a/sound/soc/codecs/ak5386.c
+++ b/sound/soc/codecs/ak5386.c
@@ -74,10 +74,12 @@
 	.remove = ak5386_soc_remove,
 	.suspend = ak5386_soc_suspend,
 	.resume = ak5386_soc_resume,
-	.dapm_widgets = ak5386_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ak5386_dapm_widgets),
-	.dapm_routes = ak5386_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(ak5386_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= ak5386_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ak5386_dapm_widgets),
+		.dapm_routes		= ak5386_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(ak5386_dapm_routes),
+	},
 };
 
 static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai,
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c
index 4d3ba33..adb80d8 100644
--- a/sound/soc/codecs/alc5632.c
+++ b/sound/soc/codecs/alc5632.c
@@ -1072,12 +1072,14 @@
 	.set_bias_level = alc5632_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = alc5632_snd_controls,
-	.num_controls = ARRAY_SIZE(alc5632_snd_controls),
-	.dapm_widgets = alc5632_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(alc5632_dapm_widgets),
-	.dapm_routes = alc5632_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(alc5632_dapm_routes),
+	.component_driver = {
+		.controls		= alc5632_snd_controls,
+		.num_controls		= ARRAY_SIZE(alc5632_snd_controls),
+		.dapm_widgets		= alc5632_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(alc5632_dapm_widgets),
+		.dapm_routes		= alc5632_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(alc5632_dapm_routes),
+	},
 };
 
 static const struct regmap_config alc5632_regmap = {
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index ecfdbfc..846ca07 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -109,7 +109,7 @@
 		break;
 	}
 
-	return 0;
+	return arizona_out_ev(w, kcontrol, event);
 }
 
 static irqreturn_t arizona_thermal_warn(int irq, void *data)
@@ -159,12 +159,14 @@
 static const struct snd_soc_dapm_widget arizona_spkl =
 	SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM,
 			   ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
-			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD);
 
 static const struct snd_soc_dapm_widget arizona_spkr =
 	SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,
 			   ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
-			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD);
 
 int arizona_init_spk(struct snd_soc_codec *codec)
 {
@@ -864,6 +866,7 @@
 {
 	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct arizona *arizona = priv->arizona;
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -877,6 +880,18 @@
 			priv->out_up_pending++;
 			priv->out_up_delay += 17;
 			break;
+		case ARIZONA_OUT4L_ENA_SHIFT:
+		case ARIZONA_OUT4R_ENA_SHIFT:
+			priv->out_up_pending++;
+			switch (arizona->type) {
+			case WM5102:
+			case WM8997:
+				break;
+			default:
+				priv->out_up_delay += 10;
+				break;
+			}
+			break;
 		default:
 			break;
 		}
@@ -889,8 +904,12 @@
 		case ARIZONA_OUT2R_ENA_SHIFT:
 		case ARIZONA_OUT3L_ENA_SHIFT:
 		case ARIZONA_OUT3R_ENA_SHIFT:
+		case ARIZONA_OUT4L_ENA_SHIFT:
+		case ARIZONA_OUT4R_ENA_SHIFT:
 			priv->out_up_pending--;
-			if (!priv->out_up_pending) {
+			if (!priv->out_up_pending && priv->out_up_delay) {
+				dev_dbg(codec->dev, "Power up delay: %d\n",
+					priv->out_up_delay);
 				msleep(priv->out_up_delay);
 				priv->out_up_delay = 0;
 			}
@@ -911,6 +930,21 @@
 			priv->out_down_pending++;
 			priv->out_down_delay++;
 			break;
+		case ARIZONA_OUT4L_ENA_SHIFT:
+		case ARIZONA_OUT4R_ENA_SHIFT:
+			priv->out_down_pending++;
+			switch (arizona->type) {
+			case WM5102:
+			case WM8997:
+				break;
+			case WM8998:
+			case WM1814:
+				priv->out_down_delay += 5;
+				break;
+			default:
+				priv->out_down_delay++;
+				break;
+			}
 		default:
 			break;
 		}
@@ -923,8 +957,12 @@
 		case ARIZONA_OUT2R_ENA_SHIFT:
 		case ARIZONA_OUT3L_ENA_SHIFT:
 		case ARIZONA_OUT3R_ENA_SHIFT:
+		case ARIZONA_OUT4L_ENA_SHIFT:
+		case ARIZONA_OUT4R_ENA_SHIFT:
 			priv->out_down_pending--;
-			if (!priv->out_down_pending) {
+			if (!priv->out_down_pending && priv->out_down_delay) {
+				dev_dbg(codec->dev, "Power down delay: %d\n",
+					priv->out_down_delay);
 				msleep(priv->out_down_delay);
 				priv->out_down_delay = 0;
 			}
@@ -1920,8 +1958,8 @@
 
 struct arizona_fll_cfg {
 	int n;
-	int theta;
-	int lambda;
+	unsigned int theta;
+	unsigned int lambda;
 	int refdiv;
 	int outdiv;
 	int fratio;
@@ -2188,13 +2226,13 @@
 				 ARIZONA_FLL1_CTRL_UPD | cfg->n);
 }
 
-static int arizona_is_enabled_fll(struct arizona_fll *fll)
+static int arizona_is_enabled_fll(struct arizona_fll *fll, int base)
 {
 	struct arizona *arizona = fll->arizona;
 	unsigned int reg;
 	int ret;
 
-	ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
+	ret = regmap_read(arizona->regmap, base + 1, &reg);
 	if (ret != 0) {
 		arizona_fll_err(fll, "Failed to read current state: %d\n",
 				ret);
@@ -2208,21 +2246,24 @@
 {
 	struct arizona *arizona = fll->arizona;
 	bool use_sync = false;
-	int already_enabled = arizona_is_enabled_fll(fll);
+	int already_enabled = arizona_is_enabled_fll(fll, fll->base);
+	int sync_enabled = arizona_is_enabled_fll(fll, fll->base + 0x10);
 	struct arizona_fll_cfg cfg;
 	int i;
 	unsigned int val;
 
 	if (already_enabled < 0)
 		return already_enabled;
+	if (sync_enabled < 0)
+		return sync_enabled;
 
 	if (already_enabled) {
 		/* Facilitate smooth refclk across the transition */
-		regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9,
-					 ARIZONA_FLL1_GAIN_MASK, 0);
 		regmap_update_bits(fll->arizona->regmap, fll->base + 1,
 				   ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
 		udelay(32);
+		regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9,
+					 ARIZONA_FLL1_GAIN_MASK, 0);
 	}
 
 	/*
@@ -2233,6 +2274,10 @@
 	    fll->ref_src != fll->sync_src) {
 		arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
 
+		/* Ref path hardcodes lambda to 65536 when sync is on */
+		if (fll->sync_src >= 0 && cfg.lambda)
+			cfg.theta = (cfg.theta * (1 << 16)) / cfg.lambda;
+
 		arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
 				  false);
 		if (fll->sync_src >= 0) {
@@ -2255,6 +2300,9 @@
 		return -EINVAL;
 	}
 
+	if (already_enabled && !!sync_enabled != use_sync)
+		arizona_fll_warn(fll, "Synchroniser changed on active FLL\n");
+
 	/*
 	 * Increase the bandwidth if we're not using a low frequency
 	 * sync source.
@@ -2268,14 +2316,14 @@
 					 ARIZONA_FLL1_SYNC_BW);
 
 	if (!already_enabled)
-		pm_runtime_get(arizona->dev);
+		pm_runtime_get_sync(arizona->dev);
 
-	regmap_update_bits_async(arizona->regmap, fll->base + 1,
-				 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
 	if (use_sync)
 		regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
 					 ARIZONA_FLL1_SYNC_ENA,
 					 ARIZONA_FLL1_SYNC_ENA);
+	regmap_update_bits_async(arizona->regmap, fll->base + 1,
+				 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
 
 	if (already_enabled)
 		regmap_update_bits_async(arizona->regmap, fll->base + 1,
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index 69da1ef..850aa33 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -190,20 +190,21 @@
 
 #define ARIZONA_DSP_ROUTES(name) \
 	{ name, NULL, name " Preloader"}, \
-	{ name " Preloader", NULL, name " Aux 1" }, \
-	{ name " Preloader", NULL, name " Aux 2" }, \
-	{ name " Preloader", NULL, name " Aux 3" }, \
-	{ name " Preloader", NULL, name " Aux 4" }, \
-	{ name " Preloader", NULL, name " Aux 5" }, \
-	{ name " Preloader", NULL, name " Aux 6" }, \
+	{ name " Preloader", NULL, "SYSCLK" }, \
+	{ name, NULL, name " Aux 1" }, \
+	{ name, NULL, name " Aux 2" }, \
+	{ name, NULL, name " Aux 3" }, \
+	{ name, NULL, name " Aux 4" }, \
+	{ name, NULL, name " Aux 5" }, \
+	{ name, NULL, name " Aux 6" }, \
 	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 1"), \
 	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 2"), \
 	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 3"), \
 	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 4"), \
 	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 5"), \
 	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 6"), \
-	ARIZONA_MIXER_ROUTES(name " Preloader", name "L"), \
-	ARIZONA_MIXER_ROUTES(name " Preloader", name "R")
+	ARIZONA_MIXER_ROUTES(name, name "L"), \
+	ARIZONA_MIXER_ROUTES(name, name "R")
 
 #define ARIZONA_EQ_CONTROL(xname, xbase)                      \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,   \
diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c
index 2a8d0ee..8014e69 100644
--- a/sound/soc/codecs/bt-sco.c
+++ b/sound/soc/codecs/bt-sco.c
@@ -63,10 +63,12 @@
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_bt_sco = {
-	.dapm_widgets = bt_sco_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(bt_sco_widgets),
-	.dapm_routes = bt_sco_routes,
-	.num_dapm_routes = ARRAY_SIZE(bt_sco_routes),
+	.component_driver = {
+		.dapm_widgets		= bt_sco_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(bt_sco_widgets),
+		.dapm_routes		= bt_sco_routes,
+		.num_dapm_routes	= ARRAY_SIZE(bt_sco_routes),
+	},
 };
 
 static int bt_sco_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c
index 1c895a5..7a2d9a2 100644
--- a/sound/soc/codecs/cq93vc.c
+++ b/sound/soc/codecs/cq93vc.c
@@ -131,8 +131,10 @@
 static struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
 	.set_bias_level = cq93vc_set_bias_level,
 	.get_regmap = cq93vc_get_regmap,
-	.controls = cq93vc_snd_controls,
-	.num_controls = ARRAY_SIZE(cq93vc_snd_controls),
+	.component_driver = {
+		.controls = cq93vc_snd_controls,
+		.num_controls = ARRAY_SIZE(cq93vc_snd_controls),
+	},
 };
 
 static int cq93vc_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c
index 287d137..7e98062 100644
--- a/sound/soc/codecs/cs35l32.c
+++ b/sound/soc/codecs/cs35l32.c
@@ -231,13 +231,14 @@
 static const 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),
+	.component_driver = {
+		.controls		= cs35l32_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs35l32_snd_controls),
+		.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),
+	},
 };
 
 /* Current and threshold powerup sequence Pg37 in datasheet */
diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c
index 6f9c1ad..6df29fa 100644
--- a/sound/soc/codecs/cs35l33.c
+++ b/sound/soc/codecs/cs35l33.c
@@ -837,13 +837,14 @@
 	.set_bias_level = cs35l33_set_bias_level,
 	.set_sysclk = cs35l33_codec_set_sysclk,
 
-	.dapm_widgets = cs35l33_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(cs35l33_dapm_widgets),
-	.dapm_routes = cs35l33_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(cs35l33_audio_map),
-	.controls = cs35l33_snd_controls,
-	.num_controls = ARRAY_SIZE(cs35l33_snd_controls),
-
+	.component_driver = {
+		.controls		= cs35l33_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs35l33_snd_controls),
+		.dapm_widgets		= cs35l33_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs35l33_dapm_widgets),
+		.dapm_routes		= cs35l33_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(cs35l33_audio_map),
+	},
 	.idle_bias_off = true,
 };
 
diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c
index 55db19d..fd966bb 100644
--- a/sound/soc/codecs/cs4265.c
+++ b/sound/soc/codecs/cs4265.c
@@ -547,13 +547,14 @@
 static const struct snd_soc_codec_driver soc_codec_cs4265 = {
 	.set_bias_level = cs4265_set_bias_level,
 
-	.dapm_widgets = cs4265_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(cs4265_dapm_widgets),
-	.dapm_routes = cs4265_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(cs4265_audio_map),
-
-	.controls = cs4265_snd_controls,
-	.num_controls = ARRAY_SIZE(cs4265_snd_controls),
+	.component_driver = {
+		.controls		= cs4265_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs4265_snd_controls),
+		.dapm_widgets		= cs4265_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs4265_dapm_widgets),
+		.dapm_routes		= cs4265_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(cs4265_audio_map),
+	},
 };
 
 static const struct regmap_config cs4265_regmap = {
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index e07807d..18baea2 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -617,12 +617,14 @@
 	.suspend =		cs4270_soc_suspend,
 	.resume =		cs4270_soc_resume,
 
-	.controls =		cs4270_snd_controls,
-	.num_controls =		ARRAY_SIZE(cs4270_snd_controls),
-	.dapm_widgets =		cs4270_dapm_widgets,
-	.num_dapm_widgets =	ARRAY_SIZE(cs4270_dapm_widgets),
-	.dapm_routes =		cs4270_dapm_routes,
-	.num_dapm_routes =	ARRAY_SIZE(cs4270_dapm_routes),
+	.component_driver = {
+		.controls =		cs4270_snd_controls,
+		.num_controls =		ARRAY_SIZE(cs4270_snd_controls),
+		.dapm_widgets =		cs4270_dapm_widgets,
+		.num_dapm_widgets =	ARRAY_SIZE(cs4270_dapm_widgets),
+		.dapm_routes =		cs4270_dapm_routes,
+		.num_dapm_routes =	ARRAY_SIZE(cs4270_dapm_routes),
+	},
 };
 
 /*
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index 0c0010b..8c0f3b8 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -645,12 +645,14 @@
 	.suspend		= cs4271_soc_suspend,
 	.resume			= cs4271_soc_resume,
 
-	.controls		= cs4271_snd_controls,
-	.num_controls		= ARRAY_SIZE(cs4271_snd_controls),
-	.dapm_widgets		= cs4271_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(cs4271_dapm_widgets),
-	.dapm_routes		= cs4271_dapm_routes,
-	.num_dapm_routes	= ARRAY_SIZE(cs4271_dapm_routes),
+	.component_driver = {
+		.controls		= cs4271_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs4271_snd_controls),
+		.dapm_widgets		= cs4271_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs4271_dapm_widgets),
+		.dapm_routes		= cs4271_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(cs4271_dapm_routes),
+	},
 };
 
 static int cs4271_common_probe(struct device *dev,
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 35488f1..96cfe38 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -507,12 +507,14 @@
 static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
 	.probe = cs42l51_codec_probe,
 
-	.controls = cs42l51_snd_controls,
-	.num_controls = ARRAY_SIZE(cs42l51_snd_controls),
-	.dapm_widgets = cs42l51_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(cs42l51_dapm_widgets),
-	.dapm_routes = cs42l51_routes,
-	.num_dapm_routes = ARRAY_SIZE(cs42l51_routes),
+	.component_driver = {
+		.controls		= cs42l51_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs42l51_snd_controls),
+		.dapm_widgets		= cs42l51_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs42l51_dapm_widgets),
+		.dapm_routes		= cs42l51_routes,
+		.num_dapm_routes	= ARRAY_SIZE(cs42l51_routes),
+	},
 };
 
 const struct regmap_config cs42l51_regmap = {
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index 47b97fc..0d9c4a5 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -1056,13 +1056,14 @@
 	.set_bias_level = cs42l52_set_bias_level,
 	.suspend_bias_off = true,
 
-	.dapm_widgets = cs42l52_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(cs42l52_dapm_widgets),
-	.dapm_routes = cs42l52_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(cs42l52_audio_map),
-
-	.controls = cs42l52_snd_controls,
-	.num_controls = ARRAY_SIZE(cs42l52_snd_controls),
+	.component_driver = {
+		.controls		= cs42l52_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs42l52_snd_controls),
+		.dapm_widgets		= cs42l52_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs42l52_dapm_widgets),
+		.dapm_routes		= cs42l52_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(cs42l52_audio_map),
+	},
 };
 
 /* Current and threshold powerup sequence Pg37 */
diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c
index eec1ff8..54c1768 100644
--- a/sound/soc/codecs/cs42l56.c
+++ b/sound/soc/codecs/cs42l56.c
@@ -1121,13 +1121,14 @@
 	.set_bias_level = cs42l56_set_bias_level,
 	.suspend_bias_off = true,
 
-	.dapm_widgets = cs42l56_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(cs42l56_dapm_widgets),
-	.dapm_routes = cs42l56_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(cs42l56_audio_map),
-
-	.controls = cs42l56_snd_controls,
-	.num_controls = ARRAY_SIZE(cs42l56_snd_controls),
+	.component_driver = {
+		.controls		= cs42l56_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs42l56_snd_controls),
+		.dapm_widgets		= cs42l56_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs42l56_dapm_widgets),
+		.dapm_routes		= cs42l56_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(cs42l56_audio_map),
+	},
 };
 
 static const struct regmap_config cs42l56_regmap = {
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index 42a8fd4..71ba560 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -794,7 +794,7 @@
 	u8 mmcc;
 };
 
-static struct cs42l73_mclk_div cs42l73_mclk_coeffs[] = {
+static const struct cs42l73_mclk_div cs42l73_mclk_coeffs[] = {
 	/* MCLK, Sample Rate, xMMCC[5:0] */
 	{5644800, 11025, 0x30},
 	{5644800, 22050, 0x20},
@@ -844,7 +844,7 @@
 	u8 mclkdiv;
 };
 
-static struct cs42l73_mclkx_div cs42l73_mclkx_coeffs[] = {
+static const struct cs42l73_mclkx_div cs42l73_mclkx_coeffs[] = {
 	{5644800,  1, 0},	/* 5644800 */
 	{6000000,  1, 0},	/* 6000000 */
 	{6144000,  1, 0},	/* 6144000 */
@@ -1257,13 +1257,14 @@
 	.set_bias_level = cs42l73_set_bias_level,
 	.suspend_bias_off = true,
 
-	.dapm_widgets = cs42l73_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(cs42l73_dapm_widgets),
-	.dapm_routes = cs42l73_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(cs42l73_audio_map),
-
-	.controls = cs42l73_snd_controls,
-	.num_controls = ARRAY_SIZE(cs42l73_snd_controls),
+	.component_driver = {
+		.controls		= cs42l73_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs42l73_snd_controls),
+		.dapm_widgets		= cs42l73_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs42l73_dapm_widgets),
+		.dapm_routes		= cs42l73_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(cs42l73_audio_map),
+	},
 };
 
 static const struct regmap_config cs42l73_regmap = {
diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c
index 1179101..b4d8737 100644
--- a/sound/soc/codecs/cs42xx8.c
+++ b/sound/soc/codecs/cs42xx8.c
@@ -411,12 +411,14 @@
 	.probe = cs42xx8_codec_probe,
 	.idle_bias_off = true,
 
-	.controls = cs42xx8_snd_controls,
-	.num_controls = ARRAY_SIZE(cs42xx8_snd_controls),
-	.dapm_widgets = cs42xx8_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(cs42xx8_dapm_widgets),
-	.dapm_routes = cs42xx8_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(cs42xx8_dapm_routes),
+	.component_driver = {
+		.controls		= cs42xx8_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs42xx8_snd_controls),
+		.dapm_widgets		= cs42xx8_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs42xx8_dapm_widgets),
+		.dapm_routes		= cs42xx8_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(cs42xx8_dapm_routes),
+	},
 };
 
 const struct cs42xx8_driver_data cs42448_data = {
diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c
index 0ac8fc5..231ca93 100644
--- a/sound/soc/codecs/cs4349.c
+++ b/sound/soc/codecs/cs4349.c
@@ -256,13 +256,14 @@
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_cs4349 = {
-	.controls		= cs4349_snd_controls,
-	.num_controls		= ARRAY_SIZE(cs4349_snd_controls),
-
-	.dapm_widgets		= cs4349_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(cs4349_dapm_widgets),
-	.dapm_routes		= cs4349_routes,
-	.num_dapm_routes	= ARRAY_SIZE(cs4349_routes),
+	.component_driver = {
+		.controls		= cs4349_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs4349_snd_controls),
+		.dapm_widgets		= cs4349_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs4349_dapm_widgets),
+		.dapm_routes		= cs4349_routes,
+		.num_dapm_routes	= ARRAY_SIZE(cs4349_routes),
+	},
 };
 
 static const struct regmap_config cs4349_regmap = {
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c
index 954a4f5..5b22564 100644
--- a/sound/soc/codecs/cs47l24.c
+++ b/sound/soc/codecs/cs47l24.c
@@ -746,6 +746,16 @@
 	{ "IN2L", NULL, "SYSCLK" },
 	{ "IN2R", NULL, "SYSCLK" },
 
+	{ "ASRC1L", NULL, "SYSCLK" },
+	{ "ASRC1R", NULL, "SYSCLK" },
+	{ "ASRC2L", NULL, "SYSCLK" },
+	{ "ASRC2R", NULL, "SYSCLK" },
+
+	{ "ASRC1L", NULL, "ASYNCCLK" },
+	{ "ASRC1R", NULL, "ASYNCCLK" },
+	{ "ASRC2L", NULL, "ASYNCCLK" },
+	{ "ASRC2R", NULL, "ASYNCCLK" },
+
 	{ "MICBIAS1", NULL, "MICVDD" },
 	{ "MICBIAS2", NULL, "MICVDD" },
 
@@ -804,7 +814,6 @@
 	{ "AIF3 Capture", NULL, "SYSCLK" },
 
 	{ "Voice Control DSP", NULL, "DSP3" },
-	{ "Voice Control DSP", NULL, "SYSCLK" },
 
 	{ "IN1L PGA", NULL, "IN1L" },
 	{ "IN1R PGA", NULL, "IN1R" },
@@ -813,7 +822,6 @@
 	{ "IN2R PGA", NULL, "IN2R" },
 
 	{ "Audio Trace DSP", NULL, "DSP2" },
-	{ "Audio Trace DSP", NULL, "SYSCLK" },
 
 	ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
 	ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
@@ -1190,12 +1198,14 @@
 	.set_sysclk = arizona_set_sysclk,
 	.set_pll = cs47l24_set_fll,
 
-	.controls = cs47l24_snd_controls,
-	.num_controls = ARRAY_SIZE(cs47l24_snd_controls),
-	.dapm_widgets = cs47l24_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(cs47l24_dapm_widgets),
-	.dapm_routes = cs47l24_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(cs47l24_dapm_routes),
+	.component_driver = {
+		.controls		= cs47l24_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs47l24_snd_controls),
+		.dapm_widgets		= cs47l24_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs47l24_dapm_widgets),
+		.dapm_routes		= cs47l24_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(cs47l24_dapm_routes),
+	},
 };
 
 static struct snd_compr_ops cs47l24_compr_ops = {
diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c
index 2c0d9c4..cb47fb5 100644
--- a/sound/soc/codecs/cs53l30.c
+++ b/sound/soc/codecs/cs53l30.c
@@ -466,7 +466,7 @@
 	u8 mclk_int_scale;
 };
 
-static struct cs53l30_mclk_div cs53l30_mclk_coeffs[] = {
+static const struct cs53l30_mclk_div cs53l30_mclk_coeffs[] = {
 	/* NOTE: Enable MCLK_INT_SCALE to save power. */
 
 	/* MCLK, Sample Rate, asp_rate, internal_fs_ratio, mclk_int_scale */
@@ -511,7 +511,7 @@
 	u8 mclkdiv;
 };
 
-static struct cs53l30_mclkx_div cs53l30_mclkx_coeffs[] = {
+static const struct cs53l30_mclkx_div cs53l30_mclkx_coeffs[] = {
 	{5644800,  1, CS53L30_MCLK_DIV_BY_1},
 	{6000000,  1, CS53L30_MCLK_DIV_BY_1},
 	{6144000,  1, CS53L30_MCLK_DIV_BY_1},
@@ -897,13 +897,14 @@
 	.set_bias_level = cs53l30_set_bias_level,
 	.idle_bias_off = true,
 
-	.dapm_widgets = cs53l30_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(cs53l30_dapm_widgets),
-	.dapm_routes = cs53l30_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(cs53l30_dapm_routes),
-
-	.controls = cs53l30_snd_controls,
-	.num_controls = ARRAY_SIZE(cs53l30_snd_controls),
+	.component_driver = {
+		.controls		= cs53l30_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs53l30_snd_controls),
+		.dapm_widgets		= cs53l30_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs53l30_dapm_widgets),
+		.dapm_routes		= cs53l30_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(cs53l30_dapm_routes),
+	},
 };
 
 static struct regmap_config cs53l30_regmap = {
@@ -999,8 +1000,8 @@
 	/* Check if MCLK provided */
 	cs53l30->mclk = devm_clk_get(dev, "mclk");
 	if (IS_ERR(cs53l30->mclk)) {
-		if (PTR_ERR(cs53l30->mclk) == -EPROBE_DEFER) {
-			ret = -EPROBE_DEFER;
+		if (PTR_ERR(cs53l30->mclk) != -ENOENT) {
+			ret = PTR_ERR(cs53l30->mclk);
 			goto error;
 		}
 		/* Otherwise mark the mclk pointer to NULL */
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
index fb3885f..2c12471 100644
--- a/sound/soc/codecs/cx20442.c
+++ b/sound/soc/codecs/cx20442.c
@@ -407,10 +407,12 @@
 	.reg_word_size = sizeof(u8),
 	.read = cx20442_read_reg_cache,
 	.write = cx20442_write,
-	.dapm_widgets = cx20442_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(cx20442_dapm_widgets),
-	.dapm_routes = cx20442_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(cx20442_audio_map),
+	.component_driver = {
+		.dapm_widgets		= cx20442_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cx20442_dapm_widgets),
+		.dapm_routes		= cx20442_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(cx20442_audio_map),
+	},
 };
 
 static int cx20442_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index af23a61..17053df 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -1167,13 +1167,14 @@
 static struct snd_soc_codec_driver soc_codec_dev_da7210 = {
 	.probe			= da7210_probe,
 
-	.controls		= da7210_snd_controls,
-	.num_controls		= ARRAY_SIZE(da7210_snd_controls),
-
-	.dapm_widgets		= da7210_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(da7210_dapm_widgets),
-	.dapm_routes		= da7210_audio_map,
-	.num_dapm_routes	= ARRAY_SIZE(da7210_audio_map),
+	.component_driver = {
+		.controls		= da7210_snd_controls,
+		.num_controls		= ARRAY_SIZE(da7210_snd_controls),
+		.dapm_widgets		= da7210_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(da7210_dapm_widgets),
+		.dapm_routes		= da7210_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(da7210_audio_map),
+	},
 };
 
 #if IS_ENABLED(CONFIG_I2C)
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index bcf1834..12da558 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -750,11 +750,18 @@
 		snd_soc_update_bits(codec, DA7213_PC_COUNT,
 				    DA7213_PC_FREERUN_MASK, 0);
 
-		/* Slave mode, if SRM not enabled no need for status checks */
+		/* If SRM not enabled then nothing more to do */
 		pll_ctrl = snd_soc_read(codec, DA7213_PLL_CTRL);
 		if (!(pll_ctrl & DA7213_PLL_SRM_EN))
 			return 0;
 
+		/* Assist 32KHz mode PLL lock */
+		if (pll_ctrl & DA7213_PLL_32K_MODE) {
+			snd_soc_write(codec, 0xF0, 0x8B);
+			snd_soc_write(codec, 0xF2, 0x03);
+			snd_soc_write(codec, 0xF0, 0x00);
+		}
+
 		/* Check SRM has locked */
 		do {
 			pll_status = snd_soc_read(codec, DA7213_PLL_STATUS);
@@ -771,6 +778,14 @@
 
 		return 0;
 	case SND_SOC_DAPM_POST_PMD:
+		/* Revert 32KHz PLL lock udpates if applied previously */
+		pll_ctrl = snd_soc_read(codec, DA7213_PLL_CTRL);
+		if (pll_ctrl & DA7213_PLL_32K_MODE) {
+			snd_soc_write(codec, 0xF0, 0x8B);
+			snd_soc_write(codec, 0xF2, 0x01);
+			snd_soc_write(codec, 0xF0, 0x00);
+		}
+
 		/* PC free-running */
 		snd_soc_update_bits(codec, DA7213_PC_COUNT,
 				    DA7213_PC_FREERUN_MASK,
@@ -1297,10 +1312,13 @@
 
 	switch (clk_id) {
 	case DA7213_CLKSRC_MCLK:
-		da7213->mclk_squarer_en = false;
+		snd_soc_update_bits(codec, DA7213_PLL_CTRL,
+				    DA7213_PLL_MCLK_SQR_EN, 0);
 		break;
 	case DA7213_CLKSRC_MCLK_SQR:
-		da7213->mclk_squarer_en = true;
+		snd_soc_update_bits(codec, DA7213_PLL_CTRL,
+				    DA7213_PLL_MCLK_SQR_EN,
+				    DA7213_PLL_MCLK_SQR_EN);
 		break;
 	default:
 		dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
@@ -1324,7 +1342,7 @@
 	return 0;
 }
 
-/* Supported PLL input frequencies are 5MHz - 54MHz. */
+/* Supported PLL input frequencies are 32KHz, 5MHz - 54MHz. */
 static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 			      int source, unsigned int fref, unsigned int fout)
 {
@@ -1336,22 +1354,26 @@
 	u32 freq_ref;
 	u64 frac_div;
 
-	/* Reset PLL configuration */
-	snd_soc_write(codec, DA7213_PLL_CTRL, 0);
-
-	pll_ctrl = 0;
-
 	/* Workout input divider based on MCLK rate */
 	if (da7213->mclk_rate == 32768) {
+		if (!da7213->master) {
+			dev_err(codec->dev,
+				"32KHz only valid if codec is clock master\n");
+			return -EINVAL;
+		}
+
 		/* 32KHz PLL Mode */
 		indiv_bits = DA7213_PLL_INDIV_9_TO_18_MHZ;
 		indiv = DA7213_PLL_INDIV_9_TO_18_MHZ_VAL;
+		source = DA7213_SYSCLK_PLL_32KHZ;
 		freq_ref = 3750000;
-		pll_ctrl |= DA7213_PLL_32K_MODE;
+
 	} else {
-		/* 5 - 54MHz MCLK */
 		if (da7213->mclk_rate < 5000000) {
-			goto pll_err;
+			dev_err(codec->dev,
+				"PLL input clock %d below valid range\n",
+				da7213->mclk_rate);
+			return -EINVAL;
 		} else if (da7213->mclk_rate <= 9000000) {
 			indiv_bits = DA7213_PLL_INDIV_5_TO_9_MHZ;
 			indiv = DA7213_PLL_INDIV_5_TO_9_MHZ_VAL;
@@ -1365,31 +1387,43 @@
 			indiv_bits = DA7213_PLL_INDIV_36_TO_54_MHZ;
 			indiv = DA7213_PLL_INDIV_36_TO_54_MHZ_VAL;
 		} else {
-			goto pll_err;
+			dev_err(codec->dev,
+				"PLL input clock %d above valid range\n",
+				da7213->mclk_rate);
+			return -EINVAL;
 		}
 		freq_ref = (da7213->mclk_rate / indiv);
 	}
 
-	pll_ctrl |= indiv_bits;
+	pll_ctrl = indiv_bits;
 
-	/* PLL Bypass mode */
-	if (source == DA7213_SYSCLK_MCLK) {
-		snd_soc_write(codec, DA7213_PLL_CTRL, pll_ctrl);
+	/* Configure PLL */
+	switch (source) {
+	case DA7213_SYSCLK_MCLK:
+		snd_soc_update_bits(codec, DA7213_PLL_CTRL,
+				    DA7213_PLL_INDIV_MASK |
+				    DA7213_PLL_MODE_MASK, pll_ctrl);
 		return 0;
-	}
-
-	/*
-	 * If Codec is slave and SRM enabled,
-	 * freq_out is (98304000 + 90316800)/2 = 94310400
-	 */
-	if (!da7213->master && da7213->srm_en) {
-		fout = DA7213_PLL_FREQ_OUT_94310400;
+	case DA7213_SYSCLK_PLL:
+		break;
+	case DA7213_SYSCLK_PLL_SRM:
 		pll_ctrl |= DA7213_PLL_SRM_EN;
-	}
+		fout = DA7213_PLL_FREQ_OUT_94310400;
+		break;
+	case DA7213_SYSCLK_PLL_32KHZ:
+		if (da7213->mclk_rate != 32768) {
+			dev_err(codec->dev,
+				"32KHz mode only valid with 32KHz MCLK\n");
+			return -EINVAL;
+		}
 
-	/* Enable MCLK squarer if required */
-	if (da7213->mclk_squarer_en)
-		pll_ctrl |= DA7213_PLL_MCLK_SQR_EN;
+		pll_ctrl |= DA7213_PLL_32K_MODE | DA7213_PLL_SRM_EN;
+		fout = DA7213_PLL_FREQ_OUT_94310400;
+		break;
+	default:
+		dev_err(codec->dev, "Invalid PLL config\n");
+		return -EINVAL;
+	}
 
 	/* Calculate dividers for PLL */
 	pll_integer = fout / freq_ref;
@@ -1405,14 +1439,19 @@
 
 	/* Enable PLL */
 	pll_ctrl |= DA7213_PLL_EN;
-	snd_soc_write(codec, DA7213_PLL_CTRL, pll_ctrl);
+	snd_soc_update_bits(codec, DA7213_PLL_CTRL,
+			    DA7213_PLL_INDIV_MASK | DA7213_PLL_MODE_MASK,
+			    pll_ctrl);
+
+	/* Assist 32KHz mode PLL lock */
+	if (source == DA7213_SYSCLK_PLL_32KHZ) {
+		snd_soc_write(codec, 0xF0, 0x8B);
+		snd_soc_write(codec, 0xF1, 0x03);
+		snd_soc_write(codec, 0xF1, 0x01);
+		snd_soc_write(codec, 0xF0, 0x00);
+	}
 
 	return 0;
-
-pll_err:
-	dev_err(codec_dai->dev, "Unsupported PLL input frequency %d\n",
-		da7213->mclk_rate);
-	return -EINVAL;
 }
 
 /* DAI operations */
@@ -1454,11 +1493,10 @@
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-	case SND_SOC_BIAS_PREPARE:
 		break;
-	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
-			/* MCLK */
+	case SND_SOC_BIAS_PREPARE:
+		/* Enable MCLK for transition to ON state */
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
 			if (da7213->mclk) {
 				ret = clk_prepare_enable(da7213->mclk);
 				if (ret) {
@@ -1467,21 +1505,24 @@
 					return ret;
 				}
 			}
-
+		}
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
 			/* Enable VMID reference & master bias */
 			snd_soc_update_bits(codec, DA7213_REFERENCES,
 					    DA7213_VMID_EN | DA7213_BIAS_EN,
 					    DA7213_VMID_EN | DA7213_BIAS_EN);
+		} else {
+			/* Remove MCLK */
+			if (da7213->mclk)
+				clk_disable_unprepare(da7213->mclk);
 		}
 		break;
 	case SND_SOC_BIAS_OFF:
 		/* Disable VMID reference & master bias */
 		snd_soc_update_bits(codec, DA7213_REFERENCES,
 				    DA7213_VMID_EN | DA7213_BIAS_EN, 0);
-
-		/* MCLK */
-		if (da7213->mclk)
-			clk_disable_unprepare(da7213->mclk);
 		break;
 	}
 	return 0;
@@ -1605,9 +1646,6 @@
 			    DA7213_ALC_CALIB_MODE_MAN, 0);
 	da7213->alc_calib_auto = true;
 
-	/* Default to using SRM for slave mode */
-	da7213->srm_en = true;
-
 	/* Default PC counter to free-running */
 	snd_soc_update_bits(codec, DA7213_PC_COUNT, DA7213_PC_FREERUN_MASK,
 			    DA7213_PC_FREERUN_MASK);
@@ -1740,13 +1778,14 @@
 	.probe			= da7213_probe,
 	.set_bias_level		= da7213_set_bias_level,
 
-	.controls		= da7213_snd_controls,
-	.num_controls		= ARRAY_SIZE(da7213_snd_controls),
-
-	.dapm_widgets		= da7213_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(da7213_dapm_widgets),
-	.dapm_routes		= da7213_audio_map,
-	.num_dapm_routes	= ARRAY_SIZE(da7213_audio_map),
+	.component_driver = {
+		.controls		= da7213_snd_controls,
+		.num_controls		= ARRAY_SIZE(da7213_snd_controls),
+		.dapm_widgets		= da7213_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(da7213_dapm_widgets),
+		.dapm_routes		= da7213_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(da7213_audio_map),
+	},
 };
 
 static const struct regmap_config da7213_regmap_config = {
diff --git a/sound/soc/codecs/da7213.h b/sound/soc/codecs/da7213.h
index fbb7a35..16ef56f 100644
--- a/sound/soc/codecs/da7213.h
+++ b/sound/soc/codecs/da7213.h
@@ -172,6 +172,7 @@
 #define DA7213_PLL_32K_MODE					(0x1 << 5)
 #define DA7213_PLL_SRM_EN					(0x1 << 6)
 #define DA7213_PLL_EN						(0x1 << 7)
+#define DA7213_PLL_MODE_MASK					(0x7 << 5)
 
 /* DA7213_DAI_CLK_MODE = 0x28 */
 #define DA7213_DAI_BCLKS_PER_WCLK_32				(0x0 << 0)
@@ -499,8 +500,6 @@
 #define DA7213_ALC_AVG_ITERATIONS	5
 
 /* PLL related */
-#define DA7213_SYSCLK_MCLK			0
-#define DA7213_SYSCLK_PLL			1
 #define DA7213_PLL_FREQ_OUT_90316800		90316800
 #define DA7213_PLL_FREQ_OUT_98304000		98304000
 #define DA7213_PLL_FREQ_OUT_94310400		94310400
@@ -515,6 +514,13 @@
 	DA7213_CLKSRC_MCLK_SQR,
 };
 
+enum da7213_sys_clk {
+	DA7213_SYSCLK_MCLK = 0,
+	DA7213_SYSCLK_PLL,
+	DA7213_SYSCLK_PLL_SRM,
+	DA7213_SYSCLK_PLL_32KHZ
+};
+
 /* Codec private data */
 struct da7213_priv {
 	struct regmap *regmap;
@@ -522,8 +528,6 @@
 	unsigned int mclk_rate;
 	int clk_src;
 	bool master;
-	bool mclk_squarer_en;
-	bool srm_en;
 	bool alc_calib_auto;
 	bool alc_en;
 	struct da7213_platform_data *pdata;
diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c
index 99ce23e..c69e976 100644
--- a/sound/soc/codecs/da7218.c
+++ b/sound/soc/codecs/da7218.c
@@ -1819,7 +1819,7 @@
 	if (da7218->mclk_rate == freq)
 		return 0;
 
-	if (((freq < 2000000) && (freq != 32768)) || (freq > 54000000)) {
+	if ((freq < 2000000) || (freq > 54000000)) {
 		dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
 			freq);
 		return -EINVAL;
@@ -1866,11 +1866,8 @@
 	u32 freq_ref;
 	u64 frac_div;
 
-	/* Verify 32KHz, 2MHz - 54MHz MCLK provided, and set input divider */
-	if (da7218->mclk_rate == 32768) {
-		indiv_bits = DA7218_PLL_INDIV_9_TO_18_MHZ;
-		indiv = DA7218_PLL_INDIV_9_TO_18_MHZ_VAL;
-	} else if (da7218->mclk_rate < 2000000) {
+	/* Verify 2MHz - 54MHz MCLK provided, and set input divider */
+	if (da7218->mclk_rate < 2000000) {
 		dev_err(codec->dev, "PLL input clock %d below valid range\n",
 			da7218->mclk_rate);
 		return -EINVAL;
@@ -1911,9 +1908,6 @@
 	case DA7218_SYSCLK_PLL_SRM:
 		pll_ctrl |= DA7218_PLL_MODE_SRM;
 		break;
-	case DA7218_SYSCLK_PLL_32KHZ:
-		pll_ctrl |= DA7218_PLL_MODE_32KHZ;
-		break;
 	default:
 		dev_err(codec->dev, "Invalid PLL config\n");
 		return -EINVAL;
@@ -2589,20 +2583,22 @@
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-	case SND_SOC_BIAS_PREPARE:
 		break;
-	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
-			/* MCLK */
+	case SND_SOC_BIAS_PREPARE:
+		/* Enable MCLK for transition to ON state */
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
 			if (da7218->mclk) {
 				ret = clk_prepare_enable(da7218->mclk);
 				if (ret) {
-					dev_err(codec->dev,
-						"Failed to enable mclk\n");
+					dev_err(codec->dev, "Failed to enable mclk\n");
 					return ret;
 				}
 			}
+		}
 
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
 			/* Master bias */
 			snd_soc_update_bits(codec, DA7218_REFERENCES,
 					    DA7218_BIAS_EN_MASK,
@@ -2612,6 +2608,10 @@
 			snd_soc_update_bits(codec, DA7218_LDO_CTRL,
 					    DA7218_LDO_EN_MASK,
 					    DA7218_LDO_EN_MASK);
+		} else {
+			/* Remove MCLK */
+			if (da7218->mclk)
+				clk_disable_unprepare(da7218->mclk);
 		}
 		break;
 	case SND_SOC_BIAS_OFF:
@@ -2625,10 +2625,6 @@
 			snd_soc_update_bits(codec, DA7218_REFERENCES,
 					    DA7218_BIAS_EN_MASK, 0);
 		}
-
-		/* MCLK */
-		if (da7218->mclk)
-			clk_disable_unprepare(da7218->mclk);
 		break;
 	}
 
@@ -3045,13 +3041,14 @@
 	.resume			= da7218_resume,
 	.set_bias_level		= da7218_set_bias_level,
 
-	.controls		= da7218_snd_controls,
-	.num_controls		= ARRAY_SIZE(da7218_snd_controls),
-
-	.dapm_widgets		= da7218_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(da7218_dapm_widgets),
-	.dapm_routes		= da7218_audio_map,
-	.num_dapm_routes	= ARRAY_SIZE(da7218_audio_map),
+	.component_driver = {
+		.controls		= da7218_snd_controls,
+		.num_controls		= ARRAY_SIZE(da7218_snd_controls),
+		.dapm_widgets		= da7218_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(da7218_dapm_widgets),
+		.dapm_routes		= da7218_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(da7218_audio_map),
+	},
 };
 
 
diff --git a/sound/soc/codecs/da7218.h b/sound/soc/codecs/da7218.h
index 477cd37..4f7ec21 100644
--- a/sound/soc/codecs/da7218.h
+++ b/sound/soc/codecs/da7218.h
@@ -888,7 +888,6 @@
 #define DA7218_PLL_MODE_BYPASS		(0x0 << 6)
 #define DA7218_PLL_MODE_NORMAL		(0x1 << 6)
 #define DA7218_PLL_MODE_SRM		(0x2 << 6)
-#define DA7218_PLL_MODE_32KHZ		(0x3 << 6)
 
 /* DA7218_PLL_FRAC_TOP = 0x92 */
 #define DA7218_PLL_FBDIV_FRAC_TOP_SHIFT	0
@@ -1371,7 +1370,6 @@
 	DA7218_SYSCLK_MCLK = 0,
 	DA7218_SYSCLK_PLL,
 	DA7218_SYSCLK_PLL_SRM,
-	DA7218_SYSCLK_PLL_32KHZ
 };
 
 enum da7218_dev_id {
diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c
index f0057cd..2b8914d 100644
--- a/sound/soc/codecs/da7219-aad.c
+++ b/sound/soc/codecs/da7219-aad.c
@@ -13,6 +13,7 @@
 
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/clk.h>
 #include <linux/i2c.h>
 #include <linux/property.h>
 #include <linux/pm_wakeirq.h>
@@ -114,13 +115,38 @@
 	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
 
 	u16 tonegen_freq_hptest;
-	u8 accdet_cfg8;
-	int report = 0;
+	u8 pll_srm_sts, gain_ramp_ctrl, accdet_cfg8;
+	int report = 0, ret = 0;
 
 	/* Lock DAPM and any Kcontrols that are affected by this test */
 	snd_soc_dapm_mutex_lock(dapm);
 	mutex_lock(&da7219->lock);
 
+	/* Ensure MCLK is available for HP test procedure */
+	if (da7219->mclk) {
+		ret = clk_prepare_enable(da7219->mclk);
+		if (ret) {
+			dev_err(codec->dev, "Failed to enable mclk - %d\n", ret);
+			mutex_unlock(&da7219->lock);
+			snd_soc_dapm_mutex_unlock(dapm);
+			return;
+		}
+	}
+
+	/*
+	 * If MCLK not present, then we're using the internal oscillator and
+	 * require different frequency settings to achieve the same result.
+	 */
+	pll_srm_sts = snd_soc_read(codec, DA7219_PLL_SRM_STS);
+	if (pll_srm_sts & DA7219_PLL_SRM_STS_MCLK)
+		tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ);
+	else
+		tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC);
+
+	/* Ensure gain ramping at fastest rate */
+	gain_ramp_ctrl = snd_soc_read(codec, DA7219_GAIN_RAMP_CTRL);
+	snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL, DA7219_GAIN_RAMP_RATE_X8);
+
 	/* Bypass cache so it saves current settings */
 	regcache_cache_bypass(da7219->regmap, true);
 
@@ -183,9 +209,15 @@
 	snd_soc_write(codec, DA7219_HP_R_CTRL,
 		      DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK);
 
+	/*
+	 * If we're running from the internal oscillator then give audio paths
+	 * time to settle before running test.
+	 */
+	if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK))
+		msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY);
+
 	/* Configure & start Tone Generator */
 	snd_soc_write(codec, DA7219_TONE_GEN_ON_PER, DA7219_BEEP_ON_PER_MASK);
-	tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ);
 	regmap_raw_write(da7219->regmap, DA7219_TONE_GEN_FREQ1_L,
 			 &tonegen_freq_hptest, sizeof(tonegen_freq_hptest));
 	snd_soc_update_bits(codec, DA7219_TONE_GEN_CFG2,
@@ -244,12 +276,26 @@
 	snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_8,
 			    DA7219_HPTEST_EN_MASK, 0);
 
+	/*
+	 * If we're running from the internal oscillator then give audio paths
+	 * time to settle before allowing headphones to be driven as required.
+	 */
+	if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK))
+		msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY);
+
+	/* Restore gain ramping rate */
+	snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL, gain_ramp_ctrl);
+
 	/* Drive Headphones/lineout */
 	snd_soc_update_bits(codec, DA7219_HP_L_CTRL, DA7219_HP_L_AMP_OE_MASK,
 			    DA7219_HP_L_AMP_OE_MASK);
 	snd_soc_update_bits(codec, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK,
 			    DA7219_HP_R_AMP_OE_MASK);
 
+	/* Remove MCLK, if previously enabled */
+	if (da7219->mclk)
+		clk_disable_unprepare(da7219->mclk);
+
 	mutex_unlock(&da7219->lock);
 	snd_soc_dapm_mutex_unlock(dapm);
 
@@ -751,6 +797,62 @@
 
 
 /*
+ * Suspend/Resume
+ */
+
+void da7219_aad_suspend(struct snd_soc_codec *codec)
+{
+	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct da7219_aad_priv *da7219_aad = da7219->aad;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	u8 micbias_ctrl;
+
+	if (da7219_aad->jack) {
+		/* Disable jack detection during suspend */
+		snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
+				    DA7219_ACCDET_EN_MASK, 0);
+
+		/*
+		 * If we have a 4-pole jack inserted, then micbias will be
+		 * enabled. We can disable micbias here, and keep a note to
+		 * re-enable it on resume. If jack removal occurred during
+		 * suspend then this will be dealt with through the IRQ handler.
+		 */
+		if (da7219_aad->jack_inserted) {
+			micbias_ctrl = snd_soc_read(codec, DA7219_MICBIAS_CTRL);
+			if (micbias_ctrl & DA7219_MICBIAS1_EN_MASK) {
+				snd_soc_dapm_disable_pin(dapm, "Mic Bias");
+				snd_soc_dapm_sync(dapm);
+				da7219_aad->micbias_resume_enable = true;
+			}
+		}
+	}
+}
+
+void da7219_aad_resume(struct snd_soc_codec *codec)
+{
+	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct da7219_aad_priv *da7219_aad = da7219->aad;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
+	if (da7219_aad->jack) {
+		/* Re-enable micbias if previously enabled for 4-pole jack */
+		if (da7219_aad->jack_inserted &&
+		    da7219_aad->micbias_resume_enable) {
+			snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
+			snd_soc_dapm_sync(dapm);
+			da7219_aad->micbias_resume_enable = false;
+		}
+
+		/* Re-enable jack detection */
+		snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
+				    DA7219_ACCDET_EN_MASK,
+				    DA7219_ACCDET_EN_MASK);
+	}
+}
+
+
+/*
  * Init/Exit
  */
 
diff --git a/sound/soc/codecs/da7219-aad.h b/sound/soc/codecs/da7219-aad.h
index 4fccf67..117a3d7 100644
--- a/sound/soc/codecs/da7219-aad.h
+++ b/sound/soc/codecs/da7219-aad.h
@@ -176,8 +176,10 @@
 #define DA7219_AAD_MICBIAS_CHK_DELAY	10
 #define DA7219_AAD_MICBIAS_CHK_RETRIES	5
 
-#define DA7219_AAD_HPTEST_RAMP_FREQ	0x28
-#define DA7219_AAD_HPTEST_PERIOD	65
+#define DA7219_AAD_HPTEST_RAMP_FREQ		0x28
+#define DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC	0x4D
+#define DA7219_AAD_HPTEST_PERIOD		65
+#define DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY	20
 
 enum da7219_aad_event_regs {
 	DA7219_AAD_IRQ_REG_A = 0,
@@ -199,12 +201,17 @@
 	struct work_struct hptest_work;
 
 	struct snd_soc_jack *jack;
+	bool micbias_resume_enable;
 	bool jack_inserted;
 };
 
 /* AAD control */
 void da7219_aad_jack_det(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
 
+/* Suspend/Resume */
+void da7219_aad_suspend(struct snd_soc_codec *codec);
+void da7219_aad_resume(struct snd_soc_codec *codec);
+
 /* Init/Exit */
 int da7219_aad_init(struct snd_soc_codec *codec);
 void da7219_aad_exit(struct snd_soc_codec *codec);
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index 50ea943..1152aa5 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -801,7 +801,7 @@
 				++i;
 				msleep(50);
 			}
-		} while ((i < DA7219_SRM_CHECK_RETRIES) & (!srm_lock));
+		} while ((i < DA7219_SRM_CHECK_RETRIES) && (!srm_lock));
 
 		if (!srm_lock)
 			dev_warn(codec->dev, "SRM failed to lock\n");
@@ -1482,6 +1482,8 @@
 	if (!pdata)
 		return NULL;
 
+	pdata->wakeup_source = device_property_read_bool(dev, "wakeup-source");
+
 	if (device_property_read_u32(dev, "dlg,micbias-lvl", &of_val32) >= 0)
 		pdata->micbias_lvl = da7219_fw_micbias_lvl(dev, of_val32);
 	else
@@ -1508,11 +1510,10 @@
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-	case SND_SOC_BIAS_PREPARE:
 		break;
-	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
-			/* MCLK */
+	case SND_SOC_BIAS_PREPARE:
+		/* Enable MCLK for transition to ON state */
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
 			if (da7219->mclk) {
 				ret = clk_prepare_enable(da7219->mclk);
 				if (ret) {
@@ -1521,22 +1522,28 @@
 					return ret;
 				}
 			}
+		}
 
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
 			/* Master bias */
 			snd_soc_update_bits(codec, DA7219_REFERENCES,
 					    DA7219_BIAS_EN_MASK,
 					    DA7219_BIAS_EN_MASK);
+
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE) {
+			/* Remove MCLK */
+			if (da7219->mclk)
+				clk_disable_unprepare(da7219->mclk);
 		}
 		break;
 	case SND_SOC_BIAS_OFF:
-		/* Only disable master bias if jack detection not active */
-		if (!da7219->aad->jack)
+		/* Only disable master bias if we're not a wake-up source */
+		if (!da7219->wakeup_source)
 			snd_soc_update_bits(codec, DA7219_REFERENCES,
 					    DA7219_BIAS_EN_MASK, 0);
 
-		/* MCLK */
-		if (da7219->mclk)
-			clk_disable_unprepare(da7219->mclk);
 		break;
 	}
 
@@ -1599,6 +1606,8 @@
 	if (pdata) {
 		u8 micbias_lvl = 0;
 
+		da7219->wakeup_source = pdata->wakeup_source;
+
 		/* Mic Bias voltages */
 		switch (pdata->micbias_lvl) {
 		case DA7219_MICBIAS_1_6V:
@@ -1733,11 +1742,11 @@
 {
 	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
+	/* Suspend AAD if we're not a wake-up source */
+	if (!da7219->wakeup_source)
+		da7219_aad_suspend(codec);
 
-	/* Put device into standby mode if jack detection disabled */
-	if (!da7219->aad->jack)
-		snd_soc_write(codec, DA7219_SYSTEM_ACTIVE, 0);
+	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
 
 	return 0;
 }
@@ -1746,13 +1755,12 @@
 {
 	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
 
-	/* Put device into active mode if previously pushed to standby */
-	if (!da7219->aad->jack)
-		snd_soc_write(codec, DA7219_SYSTEM_ACTIVE,
-			      DA7219_SYSTEM_ACTIVE_MASK);
-
 	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
+	/* Resume AAD if previously suspended */
+	if (!da7219->wakeup_source)
+		da7219_aad_resume(codec);
+
 	return 0;
 }
 #else
@@ -1767,13 +1775,14 @@
 	.resume			= da7219_resume,
 	.set_bias_level		= da7219_set_bias_level,
 
-	.controls		= da7219_snd_controls,
-	.num_controls		= ARRAY_SIZE(da7219_snd_controls),
-
-	.dapm_widgets		= da7219_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(da7219_dapm_widgets),
-	.dapm_routes		= da7219_audio_map,
-	.num_dapm_routes	= ARRAY_SIZE(da7219_audio_map),
+	.component_driver = {
+		.controls		= da7219_snd_controls,
+		.num_controls		= ARRAY_SIZE(da7219_snd_controls),
+		.dapm_widgets		= da7219_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(da7219_dapm_widgets),
+		.dapm_routes		= da7219_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(da7219_audio_map),
+	},
 };
 
 
@@ -1921,7 +1930,8 @@
 			    const struct i2c_device_id *id)
 {
 	struct da7219_priv *da7219;
-	int ret;
+	unsigned int system_active, system_status;
+	int i, ret;
 
 	da7219 = devm_kzalloc(&i2c->dev, sizeof(struct da7219_priv),
 			      GFP_KERNEL);
@@ -1937,6 +1947,37 @@
 		return ret;
 	}
 
+	regcache_cache_bypass(da7219->regmap, true);
+
+	/* Disable audio paths if still active from previous start */
+	regmap_read(da7219->regmap, DA7219_SYSTEM_ACTIVE, &system_active);
+	if (system_active) {
+		regmap_write(da7219->regmap, DA7219_GAIN_RAMP_CTRL,
+			     DA7219_GAIN_RAMP_RATE_NOMINAL);
+		regmap_write(da7219->regmap, DA7219_SYSTEM_MODES_INPUT, 0x00);
+		regmap_write(da7219->regmap, DA7219_SYSTEM_MODES_OUTPUT, 0x01);
+
+		for (i = 0; i < DA7219_SYS_STAT_CHECK_RETRIES; ++i) {
+			regmap_read(da7219->regmap, DA7219_SYSTEM_STATUS,
+				    &system_status);
+			if (!system_status)
+				break;
+
+			msleep(DA7219_SYS_STAT_CHECK_DELAY);
+		}
+	}
+
+	/* Soft reset codec */
+	regmap_write_bits(da7219->regmap, DA7219_ACCDET_CONFIG_1,
+			  DA7219_ACCDET_EN_MASK, 0);
+	regmap_write_bits(da7219->regmap, DA7219_CIF_CTRL,
+			  DA7219_CIF_REG_SOFT_RESET_MASK,
+			  DA7219_CIF_REG_SOFT_RESET_MASK);
+	regmap_write_bits(da7219->regmap, DA7219_SYSTEM_ACTIVE,
+			  DA7219_SYSTEM_ACTIVE_MASK, 0);
+
+	regcache_cache_bypass(da7219->regmap, false);
+
 	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_da7219,
 				     &da7219_dai, 1);
 	if (ret < 0) {
diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h
index ff2a2f0..66d3bad 100644
--- a/sound/soc/codecs/da7219.h
+++ b/sound/soc/codecs/da7219.h
@@ -224,6 +224,7 @@
 #define DA7219_PLL_SRM_STATE_MASK	(0xF << 0)
 #define DA7219_PLL_SRM_STATUS_SHIFT	4
 #define DA7219_PLL_SRM_STATUS_MASK	(0xF << 4)
+#define DA7219_PLL_SRM_STS_MCLK		(0x1 << 4)
 #define DA7219_PLL_SRM_STS_SRM_LOCK	(0x1 << 7)
 
 /* DA7219_DIG_ROUTING_DAI = 0x2A */
@@ -576,6 +577,8 @@
 /* DA7219_GAIN_RAMP_CTRL = 0x92 */
 #define DA7219_GAIN_RAMP_RATE_SHIFT	0
 #define DA7219_GAIN_RAMP_RATE_MASK	(0x3 << 0)
+#define DA7219_GAIN_RAMP_RATE_X8	(0x0 << 0)
+#define DA7219_GAIN_RAMP_RATE_NOMINAL	(0x1 << 0)
 #define DA7219_GAIN_RAMP_RATE_MAX	4
 
 /* DA7219_PC_COUNT = 0x94 */
@@ -770,6 +773,10 @@
 /* SRM */
 #define DA7219_SRM_CHECK_RETRIES	8
 
+/* System Controller */
+#define DA7219_SYS_STAT_CHECK_RETRIES	6
+#define DA7219_SYS_STAT_CHECK_DELAY	50
+
 enum da7219_clk_src {
 	DA7219_CLKSRC_MCLK = 0,
 	DA7219_CLKSRC_MCLK_SQR,
@@ -796,6 +803,7 @@
 	struct da7219_aad_priv *aad;
 	struct da7219_pdata *pdata;
 
+	bool wakeup_source;
 	struct regulator_bulk_data supplies[DA7219_NUM_SUPPLIES];
 	struct regmap *regmap;
 	struct mutex lock;
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
index 461506a..c1cc1c1 100644
--- a/sound/soc/codecs/da732x.c
+++ b/sound/soc/codecs/da732x.c
@@ -1501,12 +1501,14 @@
 
 static struct snd_soc_codec_driver soc_codec_dev_da732x = {
 	.set_bias_level		= da732x_set_bias_level,
-	.controls		= da732x_snd_controls,
-	.num_controls		= ARRAY_SIZE(da732x_snd_controls),
-	.dapm_widgets		= da732x_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(da732x_dapm_widgets),
-	.dapm_routes		= da732x_dapm_routes,
-	.num_dapm_routes	= ARRAY_SIZE(da732x_dapm_routes),
+	.component_driver = {
+		.controls		= da732x_snd_controls,
+		.num_controls		= ARRAY_SIZE(da732x_snd_controls),
+		.dapm_widgets		= da732x_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(da732x_dapm_widgets),
+		.dapm_routes		= da732x_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(da732x_dapm_routes),
+	},
 	.set_pll		= da732x_set_dai_pll,
 };
 
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c
index 0b2ede8..4efb5f8 100644
--- a/sound/soc/codecs/da9055.c
+++ b/sound/soc/codecs/da9055.c
@@ -1455,13 +1455,14 @@
 	.probe			= da9055_probe,
 	.set_bias_level		= da9055_set_bias_level,
 
-	.controls		= da9055_snd_controls,
-	.num_controls		= ARRAY_SIZE(da9055_snd_controls),
-
-	.dapm_widgets		= da9055_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(da9055_dapm_widgets),
-	.dapm_routes		= da9055_audio_map,
-	.num_dapm_routes	= ARRAY_SIZE(da9055_audio_map),
+	.component_driver = {
+		.controls		= da9055_snd_controls,
+		.num_controls		= ARRAY_SIZE(da9055_snd_controls),
+		.dapm_widgets		= da9055_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(da9055_dapm_widgets),
+		.dapm_routes		= da9055_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(da9055_audio_map),
+	},
 };
 
 static const struct regmap_config da9055_regmap_config = {
diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c
index fde5325..c82b9dc 100644
--- a/sound/soc/codecs/dmic.c
+++ b/sound/soc/codecs/dmic.c
@@ -51,10 +51,12 @@
 };
 
 static struct snd_soc_codec_driver soc_dmic = {
-	.dapm_widgets = dmic_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(dmic_dapm_widgets),
-	.dapm_routes = intercon,
-	.num_dapm_routes = ARRAY_SIZE(intercon),
+	.component_driver = {
+		.dapm_widgets		= dmic_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(dmic_dapm_widgets),
+		.dapm_routes		= intercon,
+		.num_dapm_routes	= ARRAY_SIZE(intercon),
+	},
 };
 
 static int dmic_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
index 2086d71..37722194 100644
--- a/sound/soc/codecs/es8328.c
+++ b/sound/soc/codecs/es8328.c
@@ -823,12 +823,14 @@
 	.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),
+	.component_driver = {
+		.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)
diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c
index 0b80052..926b1a4 100644
--- a/sound/soc/codecs/gtm601.c
+++ b/sound/soc/codecs/gtm601.c
@@ -52,10 +52,12 @@
 };
 
 static const struct snd_soc_codec_driver soc_codec_dev_gtm601 = {
-	.dapm_widgets = gtm601_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(gtm601_dapm_widgets),
-	.dapm_routes = gtm601_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(gtm601_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= gtm601_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(gtm601_dapm_widgets),
+		.dapm_routes		= gtm601_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(gtm601_dapm_routes),
+	},
 };
 
 static int gtm601_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 4e181b2..c602c49 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -614,7 +614,7 @@
 			(!pin->eld.eld_valid)) {
 
 		dev_warn(&hdac->hdac.dev,
-			"Failed: montior present? %d ELD valid?: %d for pin: %d\n",
+			"Failed: monitor present? %d ELD valid?: %d for pin: %d\n",
 			pin->eld.monitor_present, pin->eld.eld_valid, pin->nid);
 
 		return 0;
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index f27d115..b904492 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -24,6 +24,15 @@
 
 #include <drm/drm_crtc.h> /* This is only to get MAX_ELD_BYTES */
 
+struct hdmi_device {
+	struct device *dev;
+	struct list_head list;
+	int cnt;
+};
+#define pos_to_hdmi_device(pos)	container_of((pos), struct hdmi_device, list)
+LIST_HEAD(hdmi_device_list);
+
+#define DAI_NAME_SIZE 16
 struct hdmi_codec_priv {
 	struct hdmi_codec_pdata hcd;
 	struct snd_soc_dai_driver *daidrv;
@@ -320,7 +329,6 @@
 			 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE)
 
 static struct snd_soc_dai_driver hdmi_i2s_dai = {
-	.name = "i2s-hifi",
 	.id = DAI_ID_I2S,
 	.playback = {
 		.stream_name = "Playback",
@@ -334,7 +342,6 @@
 };
 
 static const struct snd_soc_dai_driver hdmi_spdif_dai = {
-	.name = "spdif-hifi",
 	.id = DAI_ID_SPDIF,
 	.playback = {
 		.stream_name = "Playback",
@@ -346,13 +353,37 @@
 	.ops = &hdmi_dai_ops,
 };
 
+static char hdmi_dai_name[][DAI_NAME_SIZE] = {
+	"hdmi-hifi.0",
+	"hdmi-hifi.1",
+	"hdmi-hifi.2",
+	"hdmi-hifi.3",
+};
+
+static int hdmi_of_xlate_dai_name(struct snd_soc_component *component,
+				  struct of_phandle_args *args,
+				  const char **dai_name)
+{
+	int id = args->args[0];
+
+	if (id < ARRAY_SIZE(hdmi_dai_name)) {
+		*dai_name = hdmi_dai_name[id];
+		return 0;
+	}
+
+	return -EAGAIN;
+}
+
 static struct snd_soc_codec_driver hdmi_codec = {
-	.controls = hdmi_controls,
-	.num_controls = ARRAY_SIZE(hdmi_controls),
-	.dapm_widgets = hdmi_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(hdmi_widgets),
-	.dapm_routes = hdmi_routes,
-	.num_dapm_routes = ARRAY_SIZE(hdmi_routes),
+	.component_driver = {
+		.controls		= hdmi_controls,
+		.num_controls		= ARRAY_SIZE(hdmi_controls),
+		.dapm_widgets		= hdmi_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(hdmi_widgets),
+		.dapm_routes		= hdmi_routes,
+		.num_dapm_routes	= ARRAY_SIZE(hdmi_routes),
+		.of_xlate_dai_name	= hdmi_of_xlate_dai_name,
+	},
 };
 
 static int hdmi_codec_probe(struct platform_device *pdev)
@@ -360,6 +391,8 @@
 	struct hdmi_codec_pdata *hcd = pdev->dev.platform_data;
 	struct device *dev = &pdev->dev;
 	struct hdmi_codec_priv *hcp;
+	struct hdmi_device *hd;
+	struct list_head *pos;
 	int dai_count, i = 0;
 	int ret;
 
@@ -381,6 +414,31 @@
 	if (!hcp)
 		return -ENOMEM;
 
+	hd = NULL;
+	list_for_each(pos, &hdmi_device_list) {
+		struct hdmi_device *tmp = pos_to_hdmi_device(pos);
+
+		if (tmp->dev == dev->parent) {
+			hd = tmp;
+			break;
+		}
+	}
+
+	if (!hd) {
+		hd = devm_kzalloc(dev, sizeof(*hd), GFP_KERNEL);
+		if (!hd)
+			return -ENOMEM;
+
+		hd->dev = dev->parent;
+
+		list_add_tail(&hd->list, &hdmi_device_list);
+	}
+
+	if (hd->cnt >= ARRAY_SIZE(hdmi_dai_name)) {
+		dev_err(dev, "too many hdmi codec are deteced\n");
+		return -EINVAL;
+	}
+
 	hcp->hcd = *hcd;
 	mutex_init(&hcp->current_stream_lock);
 
@@ -393,11 +451,14 @@
 		hcp->daidrv[i] = hdmi_i2s_dai;
 		hcp->daidrv[i].playback.channels_max =
 			hcd->max_i2s_channels;
+		hcp->daidrv[i].name = hdmi_dai_name[hd->cnt++];
 		i++;
 	}
 
-	if (hcd->spdif)
+	if (hcd->spdif) {
 		hcp->daidrv[i] = hdmi_spdif_dai;
+		hcp->daidrv[i].name = hdmi_dai_name[hd->cnt++];
+	}
 
 	ret = snd_soc_register_codec(dev, &hdmi_codec, hcp->daidrv,
 				     dai_count);
diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c
index 9b6e884..b918ba5 100644
--- a/sound/soc/codecs/inno_rk3036.c
+++ b/sound/soc/codecs/inno_rk3036.c
@@ -380,12 +380,14 @@
 	.probe			= rk3036_codec_probe,
 	.remove			= rk3036_codec_remove,
 	.set_bias_level		= rk3036_codec_set_bias_level,
-	.controls		= rk3036_codec_dapm_controls,
-	.num_controls		= ARRAY_SIZE(rk3036_codec_dapm_controls),
-	.dapm_routes		= rk3036_codec_dapm_routes,
-	.num_dapm_routes	= ARRAY_SIZE(rk3036_codec_dapm_routes),
-	.dapm_widgets		= rk3036_codec_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(rk3036_codec_dapm_widgets),
+	.component_driver = {
+		.controls		= rk3036_codec_dapm_controls,
+		.num_controls		= ARRAY_SIZE(rk3036_codec_dapm_controls),
+		.dapm_routes		= rk3036_codec_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rk3036_codec_dapm_routes),
+		.dapm_widgets		= rk3036_codec_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rk3036_codec_dapm_widgets),
+	},
 };
 
 static const struct regmap_config rk3036_codec_regmap_config = {
diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c
index be44837..a4b0ede 100644
--- a/sound/soc/codecs/isabelle.c
+++ b/sound/soc/codecs/isabelle.c
@@ -1089,12 +1089,14 @@
 
 static struct snd_soc_codec_driver soc_codec_dev_isabelle = {
 	.set_bias_level = isabelle_set_bias_level,
-	.controls = isabelle_snd_controls,
-	.num_controls = ARRAY_SIZE(isabelle_snd_controls),
-	.dapm_widgets = isabelle_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(isabelle_dapm_widgets),
-	.dapm_routes = isabelle_intercon,
-	.num_dapm_routes = ARRAY_SIZE(isabelle_intercon),
+	.component_driver = {
+		.controls		= isabelle_snd_controls,
+		.num_controls		= ARRAY_SIZE(isabelle_snd_controls),
+		.dapm_widgets		= isabelle_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(isabelle_dapm_widgets),
+		.dapm_routes		= isabelle_intercon,
+		.num_dapm_routes	= ARRAY_SIZE(isabelle_intercon),
+	},
 	.idle_bias_off = true,
 };
 
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
index 1f5ab99..0290fab 100644
--- a/sound/soc/codecs/jz4740.c
+++ b/sound/soc/codecs/jz4740.c
@@ -298,12 +298,14 @@
 	.set_bias_level = jz4740_codec_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = jz4740_codec_controls,
-	.num_controls = ARRAY_SIZE(jz4740_codec_controls),
-	.dapm_widgets = jz4740_codec_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(jz4740_codec_dapm_widgets),
-	.dapm_routes = jz4740_codec_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(jz4740_codec_dapm_routes),
+	.component_driver = {
+		.controls		= jz4740_codec_controls,
+		.num_controls		= ARRAY_SIZE(jz4740_codec_controls),
+		.dapm_widgets		= jz4740_codec_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(jz4740_codec_dapm_widgets),
+		.dapm_routes		= jz4740_codec_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(jz4740_codec_dapm_routes),
+	},
 };
 
 static const struct regmap_config jz4740_codec_regmap_config = {
diff --git a/sound/soc/codecs/l3.c b/sound/soc/codecs/l3.c
index 5353af5..a10ea3c 100644
--- a/sound/soc/codecs/l3.c
+++ b/sound/soc/codecs/l3.c
@@ -20,6 +20,8 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
 
 #include <sound/l3.h>
 
@@ -32,11 +34,11 @@
 	int i;
 
 	for (i = 0; i < 8; i++) {
-		adap->setclk(0);
+		adap->setclk(adap, 0);
 		udelay(adap->data_hold);
-		adap->setdat(byte & 1);
+		adap->setdat(adap, byte & 1);
 		udelay(adap->data_setup);
-		adap->setclk(1);
+		adap->setclk(adap, 1);
 		udelay(adap->clock_high);
 		byte >>= 1;
 	}
@@ -55,10 +57,10 @@
 	for (i = 0; i < len; i++) {
 		if (i) {
 			udelay(adap->mode_hold);
-			adap->setmode(0);
+			adap->setmode(adap, 0);
 			udelay(adap->mode);
 		}
-		adap->setmode(1);
+		adap->setmode(adap, 1);
 		udelay(adap->mode_setup);
 		sendbyte(adap, buf[i]);
 	}
@@ -66,26 +68,71 @@
 
 int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len)
 {
-	adap->setclk(1);
-	adap->setdat(1);
-	adap->setmode(1);
+	adap->setclk(adap, 1);
+	adap->setdat(adap, 1);
+	adap->setmode(adap, 1);
 	udelay(adap->mode);
 
-	adap->setmode(0);
+	adap->setmode(adap, 0);
 	udelay(adap->mode_setup);
 	sendbyte(adap, addr);
 	udelay(adap->mode_hold);
 
 	sendbytes(adap, data, len);
 
-	adap->setclk(1);
-	adap->setdat(1);
-	adap->setmode(0);
+	adap->setclk(adap, 1);
+	adap->setdat(adap, 1);
+	adap->setmode(adap, 0);
 
 	return len;
 }
 EXPORT_SYMBOL_GPL(l3_write);
 
+
+static void l3_set_clk(struct l3_pins *adap, int val)
+{
+	gpio_set_value(adap->gpio_clk, val);
+}
+
+static void l3_set_data(struct l3_pins *adap, int val)
+{
+	gpio_set_value(adap->gpio_data, val);
+}
+
+static void l3_set_mode(struct l3_pins *adap, int val)
+{
+	gpio_set_value(adap->gpio_mode, val);
+}
+
+int l3_set_gpio_ops(struct device *dev, struct l3_pins *adap)
+{
+	int ret;
+
+	if (!adap->use_gpios)
+		return -EINVAL;
+
+	ret = devm_gpio_request_one(dev, adap->gpio_data,
+				GPIOF_OUT_INIT_LOW, "l3_data");
+	if (ret < 0)
+		return ret;
+	adap->setdat = l3_set_data;
+
+	ret = devm_gpio_request_one(dev, adap->gpio_clk,
+				GPIOF_OUT_INIT_LOW, "l3_clk");
+	if (ret < 0)
+		return ret;
+	adap->setclk = l3_set_clk;
+
+	ret = devm_gpio_request_one(dev, adap->gpio_mode,
+				GPIOF_OUT_INIT_LOW, "l3_mode");
+	if (ret < 0)
+		return ret;
+	adap->setmode = l3_set_mode;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(l3_set_gpio_ops);
+
 MODULE_DESCRIPTION("L3 bit-banging driver");
 MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
index 9af5640..8d413c2 100644
--- a/sound/soc/codecs/lm49453.c
+++ b/sound/soc/codecs/lm49453.c
@@ -1391,12 +1391,14 @@
 
 static struct snd_soc_codec_driver soc_codec_dev_lm49453 = {
 	.set_bias_level = lm49453_set_bias_level,
-	.controls = lm49453_snd_controls,
-	.num_controls = ARRAY_SIZE(lm49453_snd_controls),
-	.dapm_widgets = lm49453_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(lm49453_dapm_widgets),
-	.dapm_routes = lm49453_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(lm49453_audio_map),
+	.component_driver = {
+		.controls		= lm49453_snd_controls,
+		.num_controls		= ARRAY_SIZE(lm49453_snd_controls),
+		.dapm_widgets		= lm49453_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(lm49453_dapm_widgets),
+		.dapm_routes		= lm49453_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(lm49453_audio_map),
+	},
 	.idle_bias_off = true,
 };
 
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index fc22804..72f7745 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -1704,12 +1704,14 @@
 	.set_bias_level = max98088_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = max98088_snd_controls,
-	.num_controls = ARRAY_SIZE(max98088_snd_controls),
-	.dapm_widgets = max98088_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(max98088_dapm_widgets),
-	.dapm_routes = max98088_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(max98088_audio_map),
+	.component_driver = {
+		.controls		= max98088_snd_controls,
+		.num_controls		= ARRAY_SIZE(max98088_snd_controls),
+		.dapm_widgets		= max98088_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(max98088_dapm_widgets),
+		.dapm_routes		= max98088_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(max98088_audio_map),
+	},
 };
 
 static int max98088_i2c_probe(struct i2c_client *i2c,
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 3577003..6f8a757 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -2108,12 +2108,14 @@
 	.suspend = max98095_suspend,
 	.resume  = max98095_resume,
 	.set_bias_level = max98095_set_bias_level,
-	.controls = max98095_snd_controls,
-	.num_controls = ARRAY_SIZE(max98095_snd_controls),
-	.dapm_widgets	  = max98095_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(max98095_dapm_widgets),
-	.dapm_routes     = max98095_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(max98095_audio_map),
+	.component_driver = {
+		.controls		= max98095_snd_controls,
+		.num_controls		= ARRAY_SIZE(max98095_snd_controls),
+		.dapm_widgets		= max98095_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(max98095_dapm_widgets),
+		.dapm_routes		= max98095_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(max98095_audio_map),
+	},
 };
 
 static int max98095_i2c_probe(struct i2c_client *i2c,
diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c
index 5b1dfb1..6a6b68a 100644
--- a/sound/soc/codecs/max98357a.c
+++ b/sound/soc/codecs/max98357a.c
@@ -74,10 +74,12 @@
 
 static struct snd_soc_codec_driver max98357a_codec_driver = {
 	.probe			= max98357a_codec_probe,
-	.dapm_widgets		= max98357a_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(max98357a_dapm_widgets),
-	.dapm_routes		= max98357a_dapm_routes,
-	.num_dapm_routes	= ARRAY_SIZE(max98357a_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= max98357a_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(max98357a_dapm_widgets),
+		.dapm_routes		= max98357a_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(max98357a_dapm_routes),
+	},
 };
 
 static const struct snd_soc_dai_ops max98357a_dai_ops = {
diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c
index 02352ed..781be9ba 100644
--- a/sound/soc/codecs/max98371.c
+++ b/sound/soc/codecs/max98371.c
@@ -426,7 +426,6 @@
 static struct i2c_driver max98371_i2c_driver = {
 	.driver = {
 		.name = "max98371",
-		.owner = THIS_MODULE,
 		.pm = NULL,
 		.of_match_table = of_match_ptr(max98371_of_match),
 	},
diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c
index c14a79d..0610840 100644
--- a/sound/soc/codecs/max9850.c
+++ b/sound/soc/codecs/max9850.c
@@ -306,12 +306,14 @@
 	.set_bias_level = max9850_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = max9850_controls,
-	.num_controls = ARRAY_SIZE(max9850_controls),
-	.dapm_widgets = max9850_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(max9850_dapm_widgets),
-	.dapm_routes = max9850_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(max9850_dapm_routes),
+	.component_driver = {
+		.controls		= max9850_controls,
+		.num_controls		= ARRAY_SIZE(max9850_controls),
+		.dapm_widgets		= max9850_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(max9850_dapm_widgets),
+		.dapm_routes		= max9850_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(max9850_dapm_routes),
+	},
 };
 
 static int max9850_i2c_probe(struct i2c_client *i2c,
diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c
index 68074c9..499bdbf 100644
--- a/sound/soc/codecs/max9860.c
+++ b/sound/soc/codecs/max9860.c
@@ -538,12 +538,14 @@
 	.set_bias_level = max9860_set_bias_level,
 	.idle_bias_off = true,
 
-	.controls = max9860_controls,
-	.num_controls = ARRAY_SIZE(max9860_controls),
-	.dapm_widgets = max9860_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(max9860_dapm_widgets),
-	.dapm_routes = max9860_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(max9860_dapm_routes),
+	.component_driver = {
+		.controls		= max9860_controls,
+		.num_controls		= ARRAY_SIZE(max9860_controls),
+		.dapm_widgets		= max9860_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(max9860_dapm_widgets),
+		.dapm_routes		= max9860_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(max9860_dapm_routes),
+	},
 };
 
 #ifdef CONFIG_PM
diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c
index 2a22fdd..42e2e40 100644
--- a/sound/soc/codecs/max9867.c
+++ b/sound/soc/codecs/max9867.c
@@ -38,11 +38,10 @@
 static DECLARE_TLV_DB_SCALE(max9860_mic_tlv, 2000, 100, 1);
 static DECLARE_TLV_DB_SCALE(max9860_adc_left_tlv, -1200, 100, 1);
 static DECLARE_TLV_DB_SCALE(max9860_adc_right_tlv, -1200, 100, 1);
-static const unsigned int max98088_micboost_tlv[] = {
-	TLV_DB_RANGE_HEAD(2),
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max98088_micboost_tlv,
 	0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
 	2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
-};
+);
 
 static const struct snd_kcontrol_new max9867_snd_controls[] = {
 	SOC_DOUBLE_R("Master Playback Volume", MAX9867_LEFTVOL,
@@ -417,12 +416,14 @@
 
 static struct snd_soc_codec_driver max9867_codec = {
 	.probe = max9867_probe,
-	.controls = max9867_snd_controls,
-	.num_controls = ARRAY_SIZE(max9867_snd_controls),
-	.dapm_routes = max9867_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(max9867_audio_map),
-	.dapm_widgets = max9867_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(max9867_dapm_widgets),
+	.component_driver = {
+		.controls		= max9867_snd_controls,
+		.num_controls		= ARRAY_SIZE(max9867_snd_controls),
+		.dapm_routes		= max9867_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(max9867_audio_map),
+		.dapm_widgets		= max9867_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(max9867_dapm_widgets),
+	},
 };
 
 static bool max9867_volatile_register(struct device *dev, unsigned int reg)
diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c
index 5990de3..327eaa2 100644
--- a/sound/soc/codecs/max98925.c
+++ b/sound/soc/codecs/max98925.c
@@ -540,12 +540,14 @@
 
 static const struct snd_soc_codec_driver soc_codec_dev_max98925 = {
 	.probe            = max98925_probe,
-	.controls = max98925_snd_controls,
-	.num_controls = ARRAY_SIZE(max98925_snd_controls),
-	.dapm_routes = max98925_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(max98925_audio_map),
-	.dapm_widgets = max98925_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(max98925_dapm_widgets),
+	.component_driver = {
+		.controls		= max98925_snd_controls,
+		.num_controls		= ARRAY_SIZE(max98925_snd_controls),
+		.dapm_routes		= max98925_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(max98925_audio_map),
+		.dapm_widgets		= max98925_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(max98925_dapm_widgets),
+	},
 };
 
 static const struct regmap_config max98925_regmap = {
diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c
index 8d14ada..1eff7e0 100644
--- a/sound/soc/codecs/max98926.c
+++ b/sound/soc/codecs/max98926.c
@@ -347,7 +347,7 @@
 		max98926_set_sense_data(max98926);
 		break;
 	default:
-		dev_err(codec->dev, "DAI clock mode unsupported");
+		dev_err(codec->dev, "DAI clock mode unsupported\n");
 		return -EINVAL;
 	}
 
@@ -364,7 +364,7 @@
 		invert = MAX98926_DAI_BCI_MASK | MAX98926_DAI_WCI_MASK;
 		break;
 	default:
-		dev_err(codec->dev, "DAI invert mode unsupported");
+		dev_err(codec->dev, "DAI invert mode unsupported\n");
 		return -EINVAL;
 	}
 
@@ -408,7 +408,7 @@
 		max98926->ch_size = 32;
 		break;
 	default:
-		dev_dbg(codec->dev, "format unsupported %d",
+		dev_dbg(codec->dev, "format unsupported %d\n",
 			params_format(params));
 		return -EINVAL;
 	}
@@ -498,12 +498,14 @@
 
 static struct snd_soc_codec_driver soc_codec_dev_max98926 = {
 	.probe	= max98926_probe,
-	.controls = max98926_snd_controls,
-	.num_controls = ARRAY_SIZE(max98926_snd_controls),
-	.dapm_routes = max98926_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(max98926_audio_map),
-	.dapm_widgets = max98926_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(max98926_dapm_widgets),
+	.component_driver = {
+		.controls		= max98926_snd_controls,
+		.num_controls		= ARRAY_SIZE(max98926_snd_controls),
+		.dapm_routes		= max98926_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(max98926_audio_map),
+		.dapm_widgets		= max98926_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(max98926_dapm_widgets),
+	},
 };
 
 static const struct regmap_config max98926_regmap = {
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c
index 3e770cb..9056270 100644
--- a/sound/soc/codecs/mc13783.c
+++ b/sound/soc/codecs/mc13783.c
@@ -737,12 +737,14 @@
 	.probe		= mc13783_probe,
 	.remove		= mc13783_remove,
 	.get_regmap	= mc13783_get_regmap,
-	.controls	= mc13783_control_list,
-	.num_controls	= ARRAY_SIZE(mc13783_control_list),
-	.dapm_widgets	= mc13783_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(mc13783_dapm_widgets),
-	.dapm_routes	= mc13783_routes,
-	.num_dapm_routes = ARRAY_SIZE(mc13783_routes),
+	.component_driver = {
+		.controls		= mc13783_control_list,
+		.num_controls		= ARRAY_SIZE(mc13783_control_list),
+		.dapm_widgets		= mc13783_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(mc13783_dapm_widgets),
+		.dapm_routes		= mc13783_routes,
+		.num_dapm_routes	= ARRAY_SIZE(mc13783_routes),
+	},
 };
 
 static int __init mc13783_codec_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
index f561c78..69e5e18 100644
--- a/sound/soc/codecs/ml26124.c
+++ b/sound/soc/codecs/ml26124.c
@@ -541,12 +541,14 @@
 	.probe =	ml26124_probe,
 	.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,
-	.num_dapm_routes = ARRAY_SIZE(ml26124_intercon),
-	.controls = ml26124_snd_controls,
-	.num_controls = ARRAY_SIZE(ml26124_snd_controls),
+	.component_driver = {
+		.controls		= ml26124_snd_controls,
+		.num_controls		= ARRAY_SIZE(ml26124_snd_controls),
+		.dapm_widgets		= ml26124_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ml26124_dapm_widgets),
+		.dapm_routes		= ml26124_intercon,
+		.num_dapm_routes	= ARRAY_SIZE(ml26124_intercon),
+	},
 };
 
 static const struct regmap_config ml26124_i2c_regmap = {
diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c
new file mode 100644
index 0000000..e455186
--- /dev/null
+++ b/sound/soc/codecs/nau8810.c
@@ -0,0 +1,884 @@
+/*
+ * nau8810.c  --  NAU8810 ALSA Soc Audio driver
+ *
+ * Copyright 2016 Nuvoton Technology Corp.
+ *
+ * Author: David Lin <ctlin0@nuvoton.com>
+ *
+ * Based on WM8974.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/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>
+
+#include "nau8810.h"
+
+#define NAU_PLL_FREQ_MAX 100000000
+#define NAU_PLL_FREQ_MIN 90000000
+#define NAU_PLL_REF_MAX 33000000
+#define NAU_PLL_REF_MIN 8000000
+#define NAU_PLL_OPTOP_MIN 6
+
+
+static const int nau8810_mclk_scaler[] = { 10, 15, 20, 30, 40, 60, 80, 120 };
+
+static const struct reg_default nau8810_reg_defaults[] = {
+	{ NAU8810_REG_POWER1, 0x0000 },
+	{ NAU8810_REG_POWER2, 0x0000 },
+	{ NAU8810_REG_POWER3, 0x0000 },
+	{ NAU8810_REG_IFACE, 0x0050 },
+	{ NAU8810_REG_COMP, 0x0000 },
+	{ NAU8810_REG_CLOCK, 0x0140 },
+	{ NAU8810_REG_SMPLR, 0x0000 },
+	{ NAU8810_REG_DAC, 0x0000 },
+	{ NAU8810_REG_DACGAIN, 0x00FF },
+	{ NAU8810_REG_ADC, 0x0100 },
+	{ NAU8810_REG_ADCGAIN, 0x00FF },
+	{ NAU8810_REG_EQ1, 0x012C },
+	{ NAU8810_REG_EQ2, 0x002C },
+	{ NAU8810_REG_EQ3, 0x002C },
+	{ NAU8810_REG_EQ4, 0x002C },
+	{ NAU8810_REG_EQ5, 0x002C },
+	{ NAU8810_REG_DACLIM1, 0x0032 },
+	{ NAU8810_REG_DACLIM2, 0x0000 },
+	{ NAU8810_REG_NOTCH1, 0x0000 },
+	{ NAU8810_REG_NOTCH2, 0x0000 },
+	{ NAU8810_REG_NOTCH3, 0x0000 },
+	{ NAU8810_REG_NOTCH4, 0x0000 },
+	{ NAU8810_REG_ALC1, 0x0038 },
+	{ NAU8810_REG_ALC2, 0x000B },
+	{ NAU8810_REG_ALC3, 0x0032 },
+	{ NAU8810_REG_NOISEGATE, 0x0000 },
+	{ NAU8810_REG_PLLN, 0x0008 },
+	{ NAU8810_REG_PLLK1, 0x000C },
+	{ NAU8810_REG_PLLK2, 0x0093 },
+	{ NAU8810_REG_PLLK3, 0x00E9 },
+	{ NAU8810_REG_ATTEN, 0x0000 },
+	{ NAU8810_REG_INPUT_SIGNAL, 0x0003 },
+	{ NAU8810_REG_PGAGAIN, 0x0010 },
+	{ NAU8810_REG_ADCBOOST, 0x0100 },
+	{ NAU8810_REG_OUTPUT, 0x0002 },
+	{ NAU8810_REG_SPKMIX, 0x0001 },
+	{ NAU8810_REG_SPKGAIN, 0x0039 },
+	{ NAU8810_REG_MONOMIX, 0x0001 },
+	{ NAU8810_REG_POWER4, 0x0000 },
+	{ NAU8810_REG_TSLOTCTL1, 0x0000 },
+	{ NAU8810_REG_TSLOTCTL2, 0x0020 },
+	{ NAU8810_REG_DEVICE_REVID, 0x0000 },
+	{ NAU8810_REG_I2C_DEVICEID, 0x001A },
+	{ NAU8810_REG_ADDITIONID, 0x00CA },
+	{ NAU8810_REG_RESERVE, 0x0124 },
+	{ NAU8810_REG_OUTCTL, 0x0001 },
+	{ NAU8810_REG_ALC1ENHAN1, 0x0010 },
+	{ NAU8810_REG_ALC1ENHAN2, 0x0000 },
+	{ NAU8810_REG_MISCCTL, 0x0000 },
+	{ NAU8810_REG_OUTTIEOFF, 0x0000 },
+	{ NAU8810_REG_AGCP2POUT, 0x0000 },
+	{ NAU8810_REG_AGCPOUT, 0x0000 },
+	{ NAU8810_REG_AMTCTL, 0x0000 },
+	{ NAU8810_REG_OUTTIEOFFMAN, 0x0000 },
+};
+
+static bool nau8810_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case NAU8810_REG_RESET ... NAU8810_REG_SMPLR:
+	case NAU8810_REG_DAC ... NAU8810_REG_DACGAIN:
+	case NAU8810_REG_ADC ... NAU8810_REG_ADCGAIN:
+	case NAU8810_REG_EQ1 ... NAU8810_REG_EQ5:
+	case NAU8810_REG_DACLIM1 ... NAU8810_REG_DACLIM2:
+	case NAU8810_REG_NOTCH1 ... NAU8810_REG_NOTCH4:
+	case NAU8810_REG_ALC1 ... NAU8810_REG_ATTEN:
+	case NAU8810_REG_INPUT_SIGNAL ... NAU8810_REG_PGAGAIN:
+	case NAU8810_REG_ADCBOOST:
+	case NAU8810_REG_OUTPUT ... NAU8810_REG_SPKMIX:
+	case NAU8810_REG_SPKGAIN:
+	case NAU8810_REG_MONOMIX:
+	case NAU8810_REG_POWER4 ... NAU8810_REG_TSLOTCTL2:
+	case NAU8810_REG_DEVICE_REVID ... NAU8810_REG_RESERVE:
+	case NAU8810_REG_OUTCTL ... NAU8810_REG_ALC1ENHAN2:
+	case NAU8810_REG_MISCCTL:
+	case NAU8810_REG_OUTTIEOFF ... NAU8810_REG_OUTTIEOFFMAN:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool nau8810_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case NAU8810_REG_RESET ... NAU8810_REG_SMPLR:
+	case NAU8810_REG_DAC ... NAU8810_REG_DACGAIN:
+	case NAU8810_REG_ADC ... NAU8810_REG_ADCGAIN:
+	case NAU8810_REG_EQ1 ... NAU8810_REG_EQ5:
+	case NAU8810_REG_DACLIM1 ... NAU8810_REG_DACLIM2:
+	case NAU8810_REG_NOTCH1 ... NAU8810_REG_NOTCH4:
+	case NAU8810_REG_ALC1 ... NAU8810_REG_ATTEN:
+	case NAU8810_REG_INPUT_SIGNAL ... NAU8810_REG_PGAGAIN:
+	case NAU8810_REG_ADCBOOST:
+	case NAU8810_REG_OUTPUT ... NAU8810_REG_SPKMIX:
+	case NAU8810_REG_SPKGAIN:
+	case NAU8810_REG_MONOMIX:
+	case NAU8810_REG_POWER4 ... NAU8810_REG_TSLOTCTL2:
+	case NAU8810_REG_OUTCTL ... NAU8810_REG_ALC1ENHAN2:
+	case NAU8810_REG_MISCCTL:
+	case NAU8810_REG_OUTTIEOFF ... NAU8810_REG_OUTTIEOFFMAN:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool nau8810_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case NAU8810_REG_RESET:
+	case NAU8810_REG_DEVICE_REVID ... NAU8810_REG_RESERVE:
+		return true;
+	default:
+		return false;
+	}
+}
+
+/* The EQ parameters get function is to get the 5 band equalizer control.
+ * The regmap raw read can't work here because regmap doesn't provide
+ * value format for value width of 9 bits. Therefore, the driver reads data
+ * from cache and makes value format according to the endianness of
+ * bytes type control element.
+ */
+static int nau8810_eq_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	struct soc_bytes_ext *params = (void *)kcontrol->private_value;
+	int i, reg, reg_val;
+	u16 *val;
+
+	val = (u16 *)ucontrol->value.bytes.data;
+	reg = NAU8810_REG_EQ1;
+	for (i = 0; i < params->max / sizeof(u16); i++) {
+		regmap_read(nau8810->regmap, reg + i, &reg_val);
+		/* conversion of 16-bit integers between native CPU format
+		 * and big endian format
+		 */
+		reg_val = cpu_to_be16(reg_val);
+		memcpy(val + i, &reg_val, sizeof(reg_val));
+	}
+
+	return 0;
+}
+
+/* The EQ parameters put function is to make configuration of 5 band equalizer
+ * control. These configuration includes central frequency, equalizer gain,
+ * cut-off frequency, bandwidth control, and equalizer path.
+ * The regmap raw write can't work here because regmap doesn't provide
+ * register and value format for register with address 7 bits and value 9 bits.
+ * Therefore, the driver makes value format according to the endianness of
+ * bytes type control element and writes data to codec.
+ */
+static int nau8810_eq_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	struct soc_bytes_ext *params = (void *)kcontrol->private_value;
+	void *data;
+	u16 *val, value;
+	int i, reg, ret;
+
+	data = kmemdup(ucontrol->value.bytes.data,
+		params->max, GFP_KERNEL | GFP_DMA);
+	if (!data)
+		return -ENOMEM;
+
+	val = (u16 *)data;
+	reg = NAU8810_REG_EQ1;
+	for (i = 0; i < params->max / sizeof(u16); i++) {
+		/* conversion of 16-bit integers between native CPU format
+		 * and big endian format
+		 */
+		value = be16_to_cpu(*(val + i));
+		ret = regmap_write(nau8810->regmap, reg + i, value);
+		if (ret) {
+			dev_err(codec->dev, "EQ configuration fail, register: %x ret: %d\n",
+				reg + i, ret);
+			kfree(data);
+			return ret;
+		}
+	}
+	kfree(data);
+
+	return 0;
+}
+
+static const char * const nau8810_companding[] = {
+	"Off", "NC", "u-law", "A-law" };
+
+static const struct soc_enum nau8810_companding_adc_enum =
+	SOC_ENUM_SINGLE(NAU8810_REG_COMP, NAU8810_ADCCM_SFT,
+		ARRAY_SIZE(nau8810_companding), nau8810_companding);
+
+static const struct soc_enum nau8810_companding_dac_enum =
+	SOC_ENUM_SINGLE(NAU8810_REG_COMP, NAU8810_DACCM_SFT,
+		ARRAY_SIZE(nau8810_companding), nau8810_companding);
+
+static const char * const nau8810_deemp[] = {
+	"None", "32kHz", "44.1kHz", "48kHz" };
+
+static const struct soc_enum nau8810_deemp_enum =
+	SOC_ENUM_SINGLE(NAU8810_REG_DAC, NAU8810_DEEMP_SFT,
+		ARRAY_SIZE(nau8810_deemp), nau8810_deemp);
+
+static const char * const nau8810_eqmode[] = {"Capture", "Playback" };
+
+static const struct soc_enum nau8810_eqmode_enum =
+	SOC_ENUM_SINGLE(NAU8810_REG_EQ1, NAU8810_EQM_SFT,
+		ARRAY_SIZE(nau8810_eqmode), nau8810_eqmode);
+
+static const char * const nau8810_alc[] = {"Normal", "Limiter" };
+
+static const struct soc_enum nau8810_alc_enum =
+	SOC_ENUM_SINGLE(NAU8810_REG_ALC3, NAU8810_ALCM_SFT,
+		ARRAY_SIZE(nau8810_alc), nau8810_alc);
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0);
+
+static const struct snd_kcontrol_new nau8810_snd_controls[] = {
+	SOC_ENUM("ADC Companding", nau8810_companding_adc_enum),
+	SOC_ENUM("DAC Companding", nau8810_companding_dac_enum),
+	SOC_ENUM("DAC De-emphasis", nau8810_deemp_enum),
+
+	SOC_ENUM("EQ Function", nau8810_eqmode_enum),
+	SND_SOC_BYTES_EXT("EQ Parameters", 10,
+		  nau8810_eq_get, nau8810_eq_put),
+
+	SOC_SINGLE("DAC Inversion Switch", NAU8810_REG_DAC,
+		NAU8810_DACPL_SFT, 1, 0),
+	SOC_SINGLE_TLV("Playback Volume", NAU8810_REG_DACGAIN,
+		NAU8810_DACGAIN_SFT, 0xff, 0, digital_tlv),
+
+	SOC_SINGLE("High Pass Filter Switch", NAU8810_REG_ADC,
+		NAU8810_HPFEN_SFT, 1, 0),
+	SOC_SINGLE("High Pass Cut Off", NAU8810_REG_ADC,
+		NAU8810_HPF_SFT, 0x7, 0),
+
+	SOC_SINGLE("ADC Inversion Switch", NAU8810_REG_ADC,
+		NAU8810_ADCPL_SFT, 1, 0),
+	SOC_SINGLE_TLV("Capture Volume", NAU8810_REG_ADCGAIN,
+		NAU8810_ADCGAIN_SFT, 0xff, 0, digital_tlv),
+
+	SOC_SINGLE_TLV("EQ1 Volume", NAU8810_REG_EQ1,
+		NAU8810_EQ1GC_SFT, 0x18, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ2 Volume", NAU8810_REG_EQ2,
+		NAU8810_EQ2GC_SFT, 0x18, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ3 Volume", NAU8810_REG_EQ3,
+		NAU8810_EQ3GC_SFT, 0x18, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ4 Volume", NAU8810_REG_EQ4,
+		NAU8810_EQ4GC_SFT, 0x18, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ5 Volume", NAU8810_REG_EQ5,
+		NAU8810_EQ5GC_SFT, 0x18, 1, eq_tlv),
+
+	SOC_SINGLE("DAC Limiter Switch", NAU8810_REG_DACLIM1,
+		NAU8810_DACLIMEN_SFT, 1, 0),
+	SOC_SINGLE("DAC Limiter Decay", NAU8810_REG_DACLIM1,
+		NAU8810_DACLIMDCY_SFT, 0xf, 0),
+	SOC_SINGLE("DAC Limiter Attack", NAU8810_REG_DACLIM1,
+		NAU8810_DACLIMATK_SFT, 0xf, 0),
+	SOC_SINGLE("DAC Limiter Threshold", NAU8810_REG_DACLIM2,
+		NAU8810_DACLIMTHL_SFT, 0x7, 0),
+	SOC_SINGLE("DAC Limiter Boost", NAU8810_REG_DACLIM2,
+		NAU8810_DACLIMBST_SFT, 0xf, 0),
+
+	SOC_ENUM("ALC Mode", nau8810_alc_enum),
+	SOC_SINGLE("ALC Enable Switch", NAU8810_REG_ALC1,
+		NAU8810_ALCEN_SFT, 1, 0),
+	SOC_SINGLE("ALC Max Volume", NAU8810_REG_ALC1,
+		NAU8810_ALCMXGAIN_SFT, 0x7, 0),
+	SOC_SINGLE("ALC Min Volume", NAU8810_REG_ALC1,
+		NAU8810_ALCMINGAIN_SFT, 0x7, 0),
+	SOC_SINGLE("ALC ZC Switch", NAU8810_REG_ALC2,
+		NAU8810_ALCZC_SFT, 1, 0),
+	SOC_SINGLE("ALC Hold", NAU8810_REG_ALC2,
+		NAU8810_ALCHT_SFT, 0xf, 0),
+	SOC_SINGLE("ALC Target", NAU8810_REG_ALC2,
+		NAU8810_ALCSL_SFT, 0xf, 0),
+	SOC_SINGLE("ALC Decay", NAU8810_REG_ALC3,
+		NAU8810_ALCDCY_SFT, 0xf, 0),
+	SOC_SINGLE("ALC Attack", NAU8810_REG_ALC3,
+		NAU8810_ALCATK_SFT, 0xf, 0),
+	SOC_SINGLE("ALC Noise Gate Switch", NAU8810_REG_NOISEGATE,
+		NAU8810_ALCNEN_SFT, 1, 0),
+	SOC_SINGLE("ALC Noise Gate Threshold", NAU8810_REG_NOISEGATE,
+		NAU8810_ALCNTH_SFT, 0x7, 0),
+
+	SOC_SINGLE("PGA ZC Switch", NAU8810_REG_PGAGAIN,
+		NAU8810_PGAZC_SFT, 1, 0),
+	SOC_SINGLE_TLV("PGA Volume", NAU8810_REG_PGAGAIN,
+		NAU8810_PGAGAIN_SFT, 0x3f, 0, inpga_tlv),
+
+	SOC_SINGLE("Speaker ZC Switch", NAU8810_REG_SPKGAIN,
+		NAU8810_SPKZC_SFT, 1, 0),
+	SOC_SINGLE("Speaker Mute Switch", NAU8810_REG_SPKGAIN,
+		NAU8810_SPKMT_SFT, 1, 0),
+	SOC_SINGLE_TLV("Speaker Volume", NAU8810_REG_SPKGAIN,
+		NAU8810_SPKGAIN_SFT, 0x3f, 0, spk_tlv),
+
+	SOC_SINGLE("Capture Boost(+20dB)", NAU8810_REG_ADCBOOST,
+		NAU8810_PGABST_SFT, 1, 0),
+	SOC_SINGLE("Mono Mute Switch", NAU8810_REG_MONOMIX,
+		NAU8810_MOUTMXMT_SFT, 1, 0),
+
+	SOC_SINGLE("DAC Oversampling Rate(128x) Switch", NAU8810_REG_DAC,
+		NAU8810_DACOS_SFT, 1, 0),
+	SOC_SINGLE("ADC Oversampling Rate(128x) Switch", NAU8810_REG_ADC,
+		NAU8810_ADCOS_SFT, 1, 0),
+};
+
+/* Speaker Output Mixer */
+static const struct snd_kcontrol_new nau8810_speaker_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Line Bypass Switch", NAU8810_REG_SPKMIX,
+		NAU8810_BYPSPK_SFT, 1, 0),
+	SOC_DAPM_SINGLE("PCM Playback Switch", NAU8810_REG_SPKMIX,
+		NAU8810_DACSPK_SFT, 1, 0),
+};
+
+/* Mono Output Mixer */
+static const struct snd_kcontrol_new nau8810_mono_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Line Bypass Switch", NAU8810_REG_MONOMIX,
+		NAU8810_BYPMOUT_SFT, 1, 0),
+	SOC_DAPM_SINGLE("PCM Playback Switch", NAU8810_REG_MONOMIX,
+		NAU8810_DACMOUT_SFT, 1, 0),
+};
+
+/* PGA Mute */
+static const struct snd_kcontrol_new nau8810_inpga_mute[] = {
+	SOC_DAPM_SINGLE("PGA Mute Switch", NAU8810_REG_PGAGAIN,
+		NAU8810_PGAMT_SFT, 1, 0),
+};
+
+/* Input PGA */
+static const struct snd_kcontrol_new nau8810_inpga[] = {
+	SOC_DAPM_SINGLE("MicN Switch", NAU8810_REG_INPUT_SIGNAL,
+		NAU8810_NMICPGA_SFT, 1, 0),
+	SOC_DAPM_SINGLE("MicP Switch", NAU8810_REG_INPUT_SIGNAL,
+		NAU8810_PMICPGA_SFT, 1, 0),
+};
+
+/* Mic Input boost vol */
+static const struct snd_kcontrol_new nau8810_mic_boost_controls =
+	SOC_DAPM_SINGLE("Mic Volume", NAU8810_REG_ADCBOOST,
+		NAU8810_PMICBSTGAIN_SFT, 0x7, 0);
+
+/* Loopback Switch */
+static const struct snd_kcontrol_new nau8810_loopback =
+	SOC_DAPM_SINGLE("Switch", NAU8810_REG_COMP,
+		NAU8810_ADDAP_SFT, 1, 0);
+
+static int check_mclk_select_pll(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	unsigned int value;
+
+	regmap_read(nau8810->regmap, NAU8810_REG_CLOCK, &value);
+	return (value & NAU8810_CLKM_MASK);
+}
+
+static const struct snd_soc_dapm_widget nau8810_dapm_widgets[] = {
+	SND_SOC_DAPM_MIXER("Speaker Mixer", NAU8810_REG_POWER3,
+		NAU8810_SPKMX_EN_SFT, 0, &nau8810_speaker_mixer_controls[0],
+		ARRAY_SIZE(nau8810_speaker_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Mono Mixer", NAU8810_REG_POWER3,
+		NAU8810_MOUTMX_EN_SFT, 0, &nau8810_mono_mixer_controls[0],
+		ARRAY_SIZE(nau8810_mono_mixer_controls)),
+	SND_SOC_DAPM_DAC("DAC", "HiFi Playback", NAU8810_REG_POWER3,
+		NAU8810_DAC_EN_SFT, 0),
+	SND_SOC_DAPM_ADC("ADC", "HiFi Capture", NAU8810_REG_POWER2,
+		NAU8810_ADC_EN_SFT, 0),
+	SND_SOC_DAPM_PGA("SpkN Out", NAU8810_REG_POWER3,
+		NAU8810_NSPK_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SpkP Out", NAU8810_REG_POWER3,
+		NAU8810_PSPK_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mono Out", NAU8810_REG_POWER3,
+		NAU8810_MOUT_EN_SFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER("Input PGA", NAU8810_REG_POWER2,
+		NAU8810_PGA_EN_SFT, 0, nau8810_inpga,
+		ARRAY_SIZE(nau8810_inpga)),
+	SND_SOC_DAPM_MIXER("Input Boost Stage", NAU8810_REG_POWER2,
+		NAU8810_BST_EN_SFT, 0, nau8810_inpga_mute,
+		ARRAY_SIZE(nau8810_inpga_mute)),
+
+	SND_SOC_DAPM_SUPPLY("Mic Bias", NAU8810_REG_POWER1,
+		NAU8810_MICBIAS_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL", NAU8810_REG_POWER1,
+		NAU8810_PLL_EN_SFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_SWITCH("Digital Loopback", SND_SOC_NOPM, 0, 0,
+		&nau8810_loopback),
+
+	SND_SOC_DAPM_INPUT("MICN"),
+	SND_SOC_DAPM_INPUT("MICP"),
+	SND_SOC_DAPM_OUTPUT("MONOOUT"),
+	SND_SOC_DAPM_OUTPUT("SPKOUTP"),
+	SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+};
+
+static const struct snd_soc_dapm_route nau8810_dapm_routes[] = {
+	{"DAC", NULL, "PLL", check_mclk_select_pll},
+
+	/* Mono output mixer */
+	{"Mono Mixer", "PCM Playback Switch", "DAC"},
+	{"Mono Mixer", "Line Bypass Switch", "Input Boost Stage"},
+
+	/* Speaker output mixer */
+	{"Speaker Mixer", "PCM Playback Switch", "DAC"},
+	{"Speaker Mixer", "Line Bypass Switch", "Input Boost Stage"},
+
+	/* Outputs */
+	{"Mono Out", NULL, "Mono Mixer"},
+	{"MONOOUT", NULL, "Mono Out"},
+	{"SpkN Out", NULL, "Speaker Mixer"},
+	{"SpkP Out", NULL, "Speaker Mixer"},
+	{"SPKOUTN", NULL, "SpkN Out"},
+	{"SPKOUTP", NULL, "SpkP Out"},
+
+	/* Input Boost Stage */
+	{"ADC", NULL, "Input Boost Stage"},
+	{"ADC", NULL, "PLL", check_mclk_select_pll},
+	{"Input Boost Stage", NULL, "Input PGA"},
+	{"Input Boost Stage", NULL, "MICP"},
+
+	/* Input PGA */
+	{"Input PGA", NULL, "Mic Bias"},
+	{"Input PGA", "MicN Switch", "MICN"},
+	{"Input PGA", "MicP Switch", "MICP"},
+
+	/* Digital Looptack */
+	{"Digital Loopback", "Switch", "ADC"},
+	{"DAC", NULL, "Digital Loopback"},
+};
+
+static int nau8810_set_sysclk(struct snd_soc_dai *dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+
+	nau8810->clk_id = clk_id;
+	nau8810->sysclk = freq;
+	dev_dbg(nau8810->dev, "master sysclk %dHz, source %s\n",
+		freq, clk_id == NAU8810_SCLK_PLL ? "PLL" : "MCLK");
+
+	return 0;
+}
+
+static int nau88l0_calc_pll(unsigned int pll_in,
+	unsigned int fs, struct nau8810_pll *pll_param)
+{
+	u64 f2, f2_max, pll_ratio;
+	int i, scal_sel;
+
+	if (pll_in > NAU_PLL_REF_MAX || pll_in < NAU_PLL_REF_MIN)
+		return -EINVAL;
+
+	f2_max = 0;
+	scal_sel = ARRAY_SIZE(nau8810_mclk_scaler);
+	for (i = 0; i < ARRAY_SIZE(nau8810_mclk_scaler); i++) {
+		f2 = 256 * fs * 4 * nau8810_mclk_scaler[i] / 10;
+		if (f2 > NAU_PLL_FREQ_MIN && f2 < NAU_PLL_FREQ_MAX &&
+			f2_max < f2) {
+			f2_max = f2;
+			scal_sel = i;
+		}
+	}
+	if (ARRAY_SIZE(nau8810_mclk_scaler) == scal_sel)
+		return -EINVAL;
+	pll_param->mclk_scaler = scal_sel;
+	f2 = f2_max;
+
+	/* Calculate the PLL 4-bit integer input and the PLL 24-bit fractional
+	 * input; round up the 24+4bit.
+	 */
+	pll_ratio = div_u64(f2 << 28, pll_in);
+	pll_param->pre_factor = 0;
+	if (((pll_ratio >> 28) & 0xF) < NAU_PLL_OPTOP_MIN) {
+		pll_ratio <<= 1;
+		pll_param->pre_factor = 1;
+	}
+	pll_param->pll_int = (pll_ratio >> 28) & 0xF;
+	pll_param->pll_frac = ((pll_ratio & 0xFFFFFFF) >> 4);
+
+	return 0;
+}
+
+static int nau8810_set_pll(struct snd_soc_dai *codec_dai, int pll_id,
+	int source, unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	struct regmap *map = nau8810->regmap;
+	struct nau8810_pll *pll_param = &nau8810->pll;
+	int ret, fs;
+
+	fs = freq_out / 256;
+	ret = nau88l0_calc_pll(freq_in, fs, pll_param);
+	if (ret < 0) {
+		dev_err(nau8810->dev, "Unsupported input clock %d\n", freq_in);
+		return ret;
+	}
+	dev_info(nau8810->dev, "pll_int=%x pll_frac=%x mclk_scaler=%x pre_factor=%x\n",
+		pll_param->pll_int, pll_param->pll_frac, pll_param->mclk_scaler,
+		pll_param->pre_factor);
+
+	regmap_update_bits(map, NAU8810_REG_PLLN,
+		NAU8810_PLLMCLK_DIV2 | NAU8810_PLLN_MASK,
+		(pll_param->pre_factor ? NAU8810_PLLMCLK_DIV2 : 0) |
+		pll_param->pll_int);
+	regmap_write(map, NAU8810_REG_PLLK1,
+		(pll_param->pll_frac >> NAU8810_PLLK1_SFT) &
+		NAU8810_PLLK1_MASK);
+	regmap_write(map, NAU8810_REG_PLLK2,
+		(pll_param->pll_frac >> NAU8810_PLLK2_SFT) &
+		NAU8810_PLLK2_MASK);
+	regmap_write(map, NAU8810_REG_PLLK3,
+		pll_param->pll_frac & NAU8810_PLLK3_MASK);
+	regmap_update_bits(map, NAU8810_REG_CLOCK, NAU8810_MCLKSEL_MASK,
+		pll_param->mclk_scaler << NAU8810_MCLKSEL_SFT);
+	regmap_update_bits(map, NAU8810_REG_CLOCK,
+		NAU8810_CLKM_MASK, NAU8810_CLKM_PLL);
+
+	return 0;
+}
+
+static int nau8810_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	u16 ctrl1_val = 0, ctrl2_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		ctrl2_val |= NAU8810_CLKIO_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		ctrl1_val |= NAU8810_AIFMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		ctrl1_val |= NAU8810_AIFMT_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		ctrl1_val |= NAU8810_AIFMT_PCM_A;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		ctrl1_val |= NAU8810_BCLKP_IB | NAU8810_FSP_IF;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		ctrl1_val |= NAU8810_BCLKP_IB;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		ctrl1_val |= NAU8810_FSP_IF;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(nau8810->regmap, NAU8810_REG_IFACE,
+		NAU8810_AIFMT_MASK | NAU8810_FSP_IF |
+		NAU8810_BCLKP_IB, ctrl1_val);
+	regmap_update_bits(nau8810->regmap, NAU8810_REG_CLOCK,
+		NAU8810_CLKIO_MASK, ctrl2_val);
+
+	return 0;
+}
+
+static int nau8810_mclk_clkdiv(struct nau8810 *nau8810, int rate)
+{
+	int i, sclk, imclk = rate * 256, div = 0;
+
+	if (!nau8810->sysclk) {
+		dev_err(nau8810->dev, "Make mclk div configuration fail because of invalid system clock\n");
+		return -EINVAL;
+	}
+
+	/* Configure the master clock prescaler div to make system
+	 * clock to approximate the internal master clock (IMCLK);
+	 * and large or equal to IMCLK.
+	 */
+	for (i = 1; i < ARRAY_SIZE(nau8810_mclk_scaler); i++) {
+		sclk = (nau8810->sysclk * 10) /
+			nau8810_mclk_scaler[i];
+		if (sclk < imclk)
+			break;
+		div = i;
+	}
+	dev_dbg(nau8810->dev,
+		"master clock prescaler %x for fs %d\n", div, rate);
+
+	/* master clock from MCLK and disable PLL */
+	regmap_update_bits(nau8810->regmap, NAU8810_REG_CLOCK,
+		NAU8810_MCLKSEL_MASK, (div << NAU8810_MCLKSEL_SFT));
+	regmap_update_bits(nau8810->regmap, NAU8810_REG_CLOCK,
+		NAU8810_CLKM_MASK, NAU8810_CLKM_MCLK);
+
+	return 0;
+}
+
+static int nau8810_pcm_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 nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	int val_len = 0, val_rate = 0, ret = 0;
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		val_len |= NAU8810_WLEN_20;
+		break;
+	case 24:
+		val_len |= NAU8810_WLEN_24;
+		break;
+	case 32:
+		val_len |= NAU8810_WLEN_32;
+		break;
+	}
+
+	switch (params_rate(params)) {
+	case 8000:
+		val_rate |= NAU8810_SMPLR_8K;
+		break;
+	case 11025:
+		val_rate |= NAU8810_SMPLR_12K;
+		break;
+	case 16000:
+		val_rate |= NAU8810_SMPLR_16K;
+		break;
+	case 22050:
+		val_rate |= NAU8810_SMPLR_24K;
+		break;
+	case 32000:
+		val_rate |= NAU8810_SMPLR_32K;
+		break;
+	case 44100:
+	case 48000:
+		break;
+	}
+
+	regmap_update_bits(nau8810->regmap, NAU8810_REG_IFACE,
+		NAU8810_WLEN_MASK, val_len);
+	regmap_update_bits(nau8810->regmap, NAU8810_REG_SMPLR,
+		NAU8810_SMPLR_MASK, val_rate);
+
+	/* If the master clock is from MCLK, provide the runtime FS for driver
+	 * to get the master clock prescaler configuration.
+	 */
+	if (nau8810->clk_id == NAU8810_SCLK_MCLK) {
+		ret = nau8810_mclk_clkdiv(nau8810, params_rate(params));
+		if (ret < 0)
+			dev_err(nau8810->dev, "MCLK div configuration fail\n");
+	}
+
+	return ret;
+}
+
+static int nau8810_set_bias_level(struct snd_soc_codec *codec,
+	enum snd_soc_bias_level level)
+{
+	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	struct regmap *map = nau8810->regmap;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		regmap_update_bits(map, NAU8810_REG_POWER1,
+			NAU8810_REFIMP_MASK, NAU8810_REFIMP_80K);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		regmap_update_bits(map, NAU8810_REG_POWER1,
+			NAU8810_IOBUF_EN | NAU8810_ABIAS_EN,
+			NAU8810_IOBUF_EN | NAU8810_ABIAS_EN);
+
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+			regcache_sync(map);
+			regmap_update_bits(map, NAU8810_REG_POWER1,
+				NAU8810_REFIMP_MASK, NAU8810_REFIMP_3K);
+			mdelay(100);
+		}
+		regmap_update_bits(map, NAU8810_REG_POWER1,
+			NAU8810_REFIMP_MASK, NAU8810_REFIMP_300K);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		regmap_write(map, NAU8810_REG_POWER1, 0);
+		regmap_write(map, NAU8810_REG_POWER2, 0);
+		regmap_write(map, NAU8810_REG_POWER3, 0);
+		break;
+	}
+
+	return 0;
+}
+
+
+#define NAU8810_RATES (SNDRV_PCM_RATE_8000_48000)
+
+#define NAU8810_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops nau8810_ops = {
+	.hw_params = nau8810_pcm_hw_params,
+	.set_fmt = nau8810_set_dai_fmt,
+	.set_sysclk = nau8810_set_sysclk,
+	.set_pll = nau8810_set_pll,
+};
+
+static struct snd_soc_dai_driver nau8810_dai = {
+	.name = "nau8810-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,   /* Only 1 channel of data */
+		.rates = NAU8810_RATES,
+		.formats = NAU8810_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,   /* Only 1 channel of data */
+		.rates = NAU8810_RATES,
+		.formats = NAU8810_FORMATS,
+	},
+	.ops = &nau8810_ops,
+	.symmetric_rates = 1,
+};
+
+static const struct regmap_config nau8810_regmap_config = {
+	.reg_bits = 7,
+	.val_bits = 9,
+
+	.max_register = NAU8810_REG_MAX,
+	.readable_reg = nau8810_readable_reg,
+	.writeable_reg = nau8810_writeable_reg,
+	.volatile_reg = nau8810_volatile_reg,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = nau8810_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(nau8810_reg_defaults),
+};
+
+static struct snd_soc_codec_driver nau8810_codec_driver = {
+	.set_bias_level = nau8810_set_bias_level,
+	.suspend_bias_off = true,
+
+	.component_driver = {
+		.controls = nau8810_snd_controls,
+		.num_controls = ARRAY_SIZE(nau8810_snd_controls),
+		.dapm_widgets = nau8810_dapm_widgets,
+		.num_dapm_widgets = ARRAY_SIZE(nau8810_dapm_widgets),
+		.dapm_routes = nau8810_dapm_routes,
+		.num_dapm_routes = ARRAY_SIZE(nau8810_dapm_routes),
+	},
+};
+
+static int nau8810_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct device *dev = &i2c->dev;
+	struct nau8810 *nau8810 = dev_get_platdata(dev);
+
+	if (!nau8810) {
+		nau8810 = devm_kzalloc(dev, sizeof(*nau8810), GFP_KERNEL);
+		if (!nau8810)
+			return -ENOMEM;
+	}
+	i2c_set_clientdata(i2c, nau8810);
+
+	nau8810->regmap = devm_regmap_init_i2c(i2c, &nau8810_regmap_config);
+	if (IS_ERR(nau8810->regmap))
+		return PTR_ERR(nau8810->regmap);
+	nau8810->dev = dev;
+
+	regmap_write(nau8810->regmap, NAU8810_REG_RESET, 0x00);
+
+	return snd_soc_register_codec(dev,
+		&nau8810_codec_driver, &nau8810_dai, 1);
+}
+
+static int nau8810_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id nau8810_i2c_id[] = {
+	{ "nau8810", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, nau8810_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id nau8810_of_match[] = {
+	{ .compatible = "nuvoton,nau8810", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, nau8810_of_match);
+#endif
+
+static struct i2c_driver nau8810_i2c_driver = {
+	.driver = {
+		.name = "nau8810",
+		.of_match_table = of_match_ptr(nau8810_of_match),
+	},
+	.probe =    nau8810_i2c_probe,
+	.remove =   nau8810_i2c_remove,
+	.id_table = nau8810_i2c_id,
+};
+
+module_i2c_driver(nau8810_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC NAU8810 driver");
+MODULE_AUTHOR("David Lin <ctlin0@nuvoton.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/nau8810.h b/sound/soc/codecs/nau8810.h
new file mode 100644
index 0000000..df88265
--- /dev/null
+++ b/sound/soc/codecs/nau8810.h
@@ -0,0 +1,281 @@
+/*
+ * NAU8810 ALSA SoC audio driver
+ *
+ * Copyright 2016 Nuvoton Technology Corp.
+ * Author: David Lin <ctlin0@nuvoton.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 __NAU8810_H__
+#define __NAU8810_H__
+
+#define NAU8810_REG_RESET		0x00
+#define NAU8810_REG_POWER1		0x01
+#define NAU8810_REG_POWER2		0x02
+#define NAU8810_REG_POWER3		0x03
+#define NAU8810_REG_IFACE		0x04
+#define NAU8810_REG_COMP		0x05
+#define NAU8810_REG_CLOCK		0x06
+#define NAU8810_REG_SMPLR		0x07
+#define NAU8810_REG_DAC		0x0A
+#define NAU8810_REG_DACGAIN		0x0B
+#define NAU8810_REG_ADC		0x0E
+#define NAU8810_REG_ADCGAIN		0x0F
+#define NAU8810_REG_EQ1		0x12
+#define NAU8810_REG_EQ2		0x13
+#define NAU8810_REG_EQ3		0x14
+#define NAU8810_REG_EQ4		0x15
+#define NAU8810_REG_EQ5		0x16
+#define NAU8810_REG_DACLIM1		0x18
+#define NAU8810_REG_DACLIM2		0x19
+#define NAU8810_REG_NOTCH1		0x1B
+#define NAU8810_REG_NOTCH2		0x1C
+#define NAU8810_REG_NOTCH3		0x1D
+#define NAU8810_REG_NOTCH4		0x1E
+#define NAU8810_REG_ALC1		0x20
+#define NAU8810_REG_ALC2		0x21
+#define NAU8810_REG_ALC3		0x22
+#define NAU8810_REG_NOISEGATE		0x23
+#define NAU8810_REG_PLLN		0x24
+#define NAU8810_REG_PLLK1		0x25
+#define NAU8810_REG_PLLK2		0x26
+#define NAU8810_REG_PLLK3		0x27
+#define NAU8810_REG_ATTEN		0x28
+#define NAU8810_REG_INPUT_SIGNAL	0x2C
+#define NAU8810_REG_PGAGAIN		0x2D
+#define NAU8810_REG_ADCBOOST		0x2F
+#define NAU8810_REG_OUTPUT		0x31
+#define NAU8810_REG_SPKMIX		0x32
+#define NAU8810_REG_SPKGAIN		0x36
+#define NAU8810_REG_MONOMIX		0x38
+#define NAU8810_REG_POWER4		0x3A
+#define NAU8810_REG_TSLOTCTL1		0x3B
+#define NAU8810_REG_TSLOTCTL2		0x3C
+#define NAU8810_REG_DEVICE_REVID	0x3E
+#define NAU8810_REG_I2C_DEVICEID	0x3F
+#define NAU8810_REG_ADDITIONID	0x40
+#define NAU8810_REG_RESERVE		0x41
+#define NAU8810_REG_OUTCTL		0x45
+#define NAU8810_REG_ALC1ENHAN1	0x46
+#define NAU8810_REG_ALC1ENHAN2	0x47
+#define NAU8810_REG_MISCCTL		0x49
+#define NAU8810_REG_OUTTIEOFF		0x4B
+#define NAU8810_REG_AGCP2POUT	0x4C
+#define NAU8810_REG_AGCPOUT		0x4D
+#define NAU8810_REG_AMTCTL		0x4E
+#define NAU8810_REG_OUTTIEOFFMAN	0x4F
+#define NAU8810_REG_MAX		NAU8810_REG_OUTTIEOFFMAN
+
+
+/* NAU8810_REG_POWER1 (0x1) */
+#define NAU8810_DCBUF_EN		(0x1 << 8)
+#define NAU8810_PLL_EN_SFT		5
+#define NAU8810_MICBIAS_EN_SFT	4
+#define NAU8810_ABIAS_EN		(0x1 << 3)
+#define NAU8810_IOBUF_EN		(0x1 << 2)
+#define NAU8810_REFIMP_MASK		0x3
+#define NAU8810_REFIMP_DIS		0x0
+#define NAU8810_REFIMP_80K		0x1
+#define NAU8810_REFIMP_300K		0x2
+#define NAU8810_REFIMP_3K		0x3
+
+/* NAU8810_REG_POWER2 (0x2) */
+#define NAU8810_BST_EN_SFT		4
+#define NAU8810_PGA_EN_SFT		2
+#define NAU8810_ADC_EN_SFT		0
+
+/* NAU8810_REG_POWER3 (0x3) */
+#define NAU8810_DAC_EN_SFT		0
+#define NAU8810_SPKMX_EN_SFT		2
+#define NAU8810_MOUTMX_EN_SFT	3
+#define NAU8810_PSPK_EN_SFT		5
+#define NAU8810_NSPK_EN_SFT		6
+#define NAU8810_MOUT_EN_SFT		7
+
+/* NAU8810_REG_IFACE (0x4) */
+#define NAU8810_AIFMT_SFT		3
+#define NAU8810_AIFMT_MASK		(0x3 << NAU8810_AIFMT_SFT)
+#define NAU8810_AIFMT_RIGHT		(0x0 << NAU8810_AIFMT_SFT)
+#define NAU8810_AIFMT_LEFT		(0x1 << NAU8810_AIFMT_SFT)
+#define NAU8810_AIFMT_I2S		(0x2 << NAU8810_AIFMT_SFT)
+#define NAU8810_AIFMT_PCM_A		(0x3 << NAU8810_AIFMT_SFT)
+#define NAU8810_WLEN_SFT		5
+#define NAU8810_WLEN_MASK		(0x3 << NAU8810_WLEN_SFT)
+#define NAU8810_WLEN_16		(0x0 << NAU8810_WLEN_SFT)
+#define NAU8810_WLEN_20		(0x1 << NAU8810_WLEN_SFT)
+#define NAU8810_WLEN_24		(0x2 << NAU8810_WLEN_SFT)
+#define NAU8810_WLEN_32		(0x3 << NAU8810_WLEN_SFT)
+#define NAU8810_FSP_IF			(0x1 << 7)
+#define NAU8810_BCLKP_IB		(0x1 << 8)
+
+/* NAU8810_REG_COMP (0x5) */
+#define NAU8810_ADDAP_SFT		0
+#define NAU8810_ADCCM_SFT		1
+#define NAU8810_DACCM_SFT		3
+
+/* NAU8810_REG_CLOCK (0x6) */
+#define NAU8810_CLKIO_MASK		0x1
+#define NAU8810_CLKIO_SLAVE		0x0
+#define NAU8810_CLKIO_MASTER		0x1
+#define NAU8810_BCLKSEL_SFT		2
+#define NAU8810_BCLKSEL_MASK		(0x7 << NAU8810_BCLKSEL_SFT)
+#define NAU8810_BCLKDIV_1		(0x0 << NAU8810_BCLKSEL_SFT)
+#define NAU8810_BCLKDIV_2		(0x1 << NAU8810_BCLKSEL_SFT)
+#define NAU8810_BCLKDIV_4		(0x2 << NAU8810_BCLKSEL_SFT)
+#define NAU8810_BCLKDIV_8		(0x3 << NAU8810_BCLKSEL_SFT)
+#define NAU8810_BCLKDIV_16		(0x4 << NAU8810_BCLKSEL_SFT)
+#define NAU8810_BCLKDIV_32		(0x5 << NAU8810_BCLKSEL_SFT)
+#define NAU8810_MCLKSEL_SFT		5
+#define NAU8810_MCLKSEL_MASK		(0x7 << NAU8810_MCLKSEL_SFT)
+#define NAU8810_CLKM_SFT		8
+#define NAU8810_CLKM_MASK		(0x1 << NAU8810_CLKM_SFT)
+#define NAU8810_CLKM_MCLK		(0x0 << NAU8810_CLKM_SFT)
+#define NAU8810_CLKM_PLL		(0x1 << NAU8810_CLKM_SFT)
+
+/* NAU8810_REG_SMPLR (0x7) */
+#define NAU8810_SMPLR_SFT		1
+#define NAU8810_SMPLR_MASK		(0x7 << NAU8810_SMPLR_SFT)
+#define NAU8810_SMPLR_48K		(0x0 << NAU8810_SMPLR_SFT)
+#define NAU8810_SMPLR_32K		(0x1 << NAU8810_SMPLR_SFT)
+#define NAU8810_SMPLR_24K		(0x2 << NAU8810_SMPLR_SFT)
+#define NAU8810_SMPLR_16K		(0x3 << NAU8810_SMPLR_SFT)
+#define NAU8810_SMPLR_12K		(0x4 << NAU8810_SMPLR_SFT)
+#define NAU8810_SMPLR_8K		(0x5 << NAU8810_SMPLR_SFT)
+
+/* NAU8810_REG_DAC (0xA) */
+#define NAU8810_DACPL_SFT		0
+#define NAU8810_DACOS_SFT		3
+#define NAU8810_DEEMP_SFT		4
+
+/* NAU8810_REG_DACGAIN (0xB) */
+#define NAU8810_DACGAIN_SFT		0
+
+/* NAU8810_REG_ADC (0xE) */
+#define NAU8810_ADCPL_SFT		0
+#define NAU8810_ADCOS_SFT		3
+#define NAU8810_HPF_SFT		4
+#define NAU8810_HPFEN_SFT		8
+
+/* NAU8810_REG_ADCGAIN (0xF) */
+#define NAU8810_ADCGAIN_SFT		0
+
+/* NAU8810_REG_EQ1 (0x12) */
+#define NAU8810_EQ1GC_SFT		0
+#define NAU8810_EQ1CF_SFT		5
+#define NAU8810_EQM_SFT		8
+
+/* NAU8810_REG_EQ2 (0x13) */
+#define NAU8810_EQ2GC_SFT		0
+#define NAU8810_EQ2CF_SFT		5
+#define NAU8810_EQ2BW_SFT		8
+
+/* NAU8810_REG_EQ3 (0x14) */
+#define NAU8810_EQ3GC_SFT		0
+#define NAU8810_EQ3CF_SFT		5
+#define NAU8810_EQ3BW_SFT		8
+
+/* NAU8810_REG_EQ4 (0x15) */
+#define NAU8810_EQ4GC_SFT		0
+#define NAU8810_EQ4CF_SFT		5
+#define NAU8810_EQ4BW_SFT		8
+
+/* NAU8810_REG_EQ5 (0x16) */
+#define NAU8810_EQ5GC_SFT		0
+#define NAU8810_EQ5CF_SFT		5
+
+/* NAU8810_REG_DACLIM1 (0x18) */
+#define NAU8810_DACLIMATK_SFT		0
+#define NAU8810_DACLIMDCY_SFT		4
+#define NAU8810_DACLIMEN_SFT		8
+
+/* NAU8810_REG_DACLIM2 (0x19) */
+#define NAU8810_DACLIMBST_SFT		0
+#define NAU8810_DACLIMTHL_SFT		4
+
+/* NAU8810_REG_ALC1 (0x20) */
+#define NAU8810_ALCMINGAIN_SFT	0
+#define NAU8810_ALCMXGAIN_SFT		3
+#define NAU8810_ALCEN_SFT		8
+
+/* NAU8810_REG_ALC2 (0x21) */
+#define NAU8810_ALCSL_SFT		0
+#define NAU8810_ALCHT_SFT		4
+#define NAU8810_ALCZC_SFT		8
+
+/* NAU8810_REG_ALC3 (0x22) */
+#define NAU8810_ALCATK_SFT		0
+#define NAU8810_ALCDCY_SFT		4
+#define NAU8810_ALCM_SFT		8
+
+/* NAU8810_REG_NOISEGATE (0x23) */
+#define NAU8810_ALCNTH_SFT		0
+#define NAU8810_ALCNEN_SFT		3
+
+/* NAU8810_REG_PLLN (0x24) */
+#define NAU8810_PLLN_MASK		0xF
+#define NAU8810_PLLMCLK_DIV2		(0x1 << 4)
+
+/* NAU8810_REG_PLLK1 (0x25) */
+#define NAU8810_PLLK1_SFT		18
+#define NAU8810_PLLK1_MASK		0x3F
+
+/* NAU8810_REG_PLLK2 (0x26) */
+#define NAU8810_PLLK2_SFT		9
+#define NAU8810_PLLK2_MASK		0x1FF
+
+/* NAU8810_REG_PLLK3 (0x27) */
+#define NAU8810_PLLK3_MASK		0x1FF
+
+/* NAU8810_REG_INPUT_SIGNAL (0x2C) */
+#define NAU8810_PMICPGA_SFT		0
+#define NAU8810_NMICPGA_SFT		1
+
+/* NAU8810_REG_PGAGAIN (0x2D) */
+#define NAU8810_PGAGAIN_SFT		0
+#define NAU8810_PGAMT_SFT		6
+#define NAU8810_PGAZC_SFT		7
+
+/* NAU8810_REG_ADCBOOST (0x2F) */
+#define NAU8810_PMICBSTGAIN_SFT	4
+#define NAU8810_PGABST_SFT		8
+
+/* NAU8810_REG_SPKMIX (0x32) */
+#define NAU8810_DACSPK_SFT		0
+#define NAU8810_BYPSPK_SFT		1
+
+/* NAU8810_REG_SPKGAIN (0x36) */
+#define NAU8810_SPKGAIN_SFT		0
+#define NAU8810_SPKMT_SFT		6
+#define NAU8810_SPKZC_SFT		7
+
+/* NAU8810_REG_MONOMIX (0x38) */
+#define NAU8810_DACMOUT_SFT		0
+#define NAU8810_BYPMOUT_SFT		1
+#define NAU8810_MOUTMXMT_SFT		6
+
+
+/* System Clock Source */
+enum {
+	NAU8810_SCLK_MCLK,
+	NAU8810_SCLK_PLL,
+};
+
+struct nau8810_pll {
+	int pre_factor;
+	int mclk_scaler;
+	int pll_frac;
+	int pll_int;
+};
+
+struct nau8810 {
+	struct device *dev;
+	struct regmap *regmap;
+	struct nau8810_pll pll;
+	int sysclk;
+	int clk_id;
+};
+
+#endif
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index 2e59a85..e643be9 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -1907,7 +1907,7 @@
 	/* Calculate the FLL 10-bit integer input and the FLL 16-bit fractional
 	 * input based on FDCO, FREF and FLL ratio.
 	 */
-	fvco = div_u64(fvco << 16, fref * fll_param->ratio);
+	fvco = div_u64(fvco_max << 16, fref * fll_param->ratio);
 	fll_param->fll_int = (fvco >> 16) & 0x3FF;
 	fll_param->fll_frac = fvco & 0xFFFF;
 	return 0;
@@ -2256,12 +2256,14 @@
 	.suspend = nau8825_suspend,
 	.resume = nau8825_resume,
 
-	.controls = nau8825_controls,
-	.num_controls = ARRAY_SIZE(nau8825_controls),
-	.dapm_widgets = nau8825_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(nau8825_dapm_widgets),
-	.dapm_routes = nau8825_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(nau8825_dapm_routes),
+	.component_driver = {
+		.controls		= nau8825_controls,
+		.num_controls		= ARRAY_SIZE(nau8825_controls),
+		.dapm_widgets		= nau8825_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(nau8825_dapm_widgets),
+		.dapm_routes		= nau8825_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(nau8825_dapm_routes),
+	},
 };
 
 static void nau8825_reset_chip(struct regmap *regmap)
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c
index 33e1fc2d..0b14efa 100644
--- a/sound/soc/codecs/pcm1681.c
+++ b/sound/soc/codecs/pcm1681.c
@@ -289,12 +289,14 @@
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_pcm1681 = {
-	.controls		= pcm1681_controls,
-	.num_controls		= ARRAY_SIZE(pcm1681_controls),
-	.dapm_widgets		= pcm1681_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(pcm1681_dapm_widgets),
-	.dapm_routes		= pcm1681_dapm_routes,
-	.num_dapm_routes	= ARRAY_SIZE(pcm1681_dapm_routes),
+	.component_driver = {
+		.controls		= pcm1681_controls,
+		.num_controls		= ARRAY_SIZE(pcm1681_controls),
+		.dapm_widgets		= pcm1681_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(pcm1681_dapm_widgets),
+		.dapm_routes		= pcm1681_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(pcm1681_dapm_routes),
+	},
 };
 
 static const struct i2c_device_id pcm1681_i2c_id[] = {
diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c
index 88fbdd1..b813a15 100644
--- a/sound/soc/codecs/pcm179x.c
+++ b/sound/soc/codecs/pcm179x.c
@@ -206,12 +206,14 @@
 EXPORT_SYMBOL_GPL(pcm179x_regmap_config);
 
 static struct snd_soc_codec_driver soc_codec_dev_pcm179x = {
-	.controls		= pcm179x_controls,
-	.num_controls		= ARRAY_SIZE(pcm179x_controls),
-	.dapm_widgets		= pcm179x_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(pcm179x_dapm_widgets),
-	.dapm_routes		= pcm179x_dapm_routes,
-	.num_dapm_routes	= ARRAY_SIZE(pcm179x_dapm_routes),
+	.component_driver = {
+		.controls		= pcm179x_controls,
+		.num_controls		= ARRAY_SIZE(pcm179x_controls),
+		.dapm_widgets		= pcm179x_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(pcm179x_dapm_widgets),
+		.dapm_routes		= pcm179x_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(pcm179x_dapm_routes),
+	},
 };
 
 int pcm179x_common_init(struct device *dev, struct regmap *regmap)
diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c
index 8fb445f..708af05 100644
--- a/sound/soc/codecs/pcm3008.c
+++ b/sound/soc/codecs/pcm3008.c
@@ -99,10 +99,12 @@
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = {
-	.dapm_widgets = pcm3008_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(pcm3008_dapm_widgets),
-	.dapm_routes = pcm3008_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(pcm3008_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= pcm3008_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(pcm3008_dapm_widgets),
+		.dapm_routes		= pcm3008_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(pcm3008_dapm_routes),
+	},
 };
 
 static int pcm3008_codec_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
index 992a77e..39bc02d 100644
--- a/sound/soc/codecs/pcm3168a.c
+++ b/sound/soc/codecs/pcm3168a.c
@@ -599,12 +599,14 @@
 
 static const struct snd_soc_codec_driver pcm3168a_driver = {
 	.idle_bias_off = true,
-	.controls = pcm3168a_snd_controls,
-	.num_controls = ARRAY_SIZE(pcm3168a_snd_controls),
-	.dapm_widgets = pcm3168a_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(pcm3168a_dapm_widgets),
-	.dapm_routes = pcm3168a_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(pcm3168a_dapm_routes)
+	.component_driver = {
+		.controls		= pcm3168a_snd_controls,
+		.num_controls		= ARRAY_SIZE(pcm3168a_snd_controls),
+		.dapm_widgets		= pcm3168a_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(pcm3168a_dapm_widgets),
+		.dapm_routes		= pcm3168a_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(pcm3168a_dapm_routes)
+	},
 };
 
 int pcm3168a_probe(struct device *dev, struct regmap *regmap)
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 047c489..72b19e6 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -1348,12 +1348,14 @@
 	.set_bias_level = pcm512x_set_bias_level,
 	.idle_bias_off = true,
 
-	.controls = pcm512x_controls,
-	.num_controls = ARRAY_SIZE(pcm512x_controls),
-	.dapm_widgets = pcm512x_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(pcm512x_dapm_widgets),
-	.dapm_routes = pcm512x_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(pcm512x_dapm_routes),
+	.component_driver = {
+		.controls		= pcm512x_controls,
+		.num_controls		= ARRAY_SIZE(pcm512x_controls),
+		.dapm_widgets		= pcm512x_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(pcm512x_dapm_widgets),
+		.dapm_routes		= pcm512x_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(pcm512x_dapm_routes),
+	},
 };
 
 static const struct regmap_range_cfg pcm512x_range = {
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index 74c0e4e..9c365a7 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -1053,12 +1053,14 @@
 	.resume = rt286_resume,
 	.set_bias_level = rt286_set_bias_level,
 	.idle_bias_off = true,
-	.controls = rt286_snd_controls,
-	.num_controls = ARRAY_SIZE(rt286_snd_controls),
-	.dapm_widgets = rt286_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(rt286_dapm_widgets),
-	.dapm_routes = rt286_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(rt286_dapm_routes),
+	.component_driver = {
+		.controls		= rt286_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt286_snd_controls),
+		.dapm_widgets		= rt286_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt286_dapm_widgets),
+		.dapm_routes		= rt286_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt286_dapm_routes),
+	},
 };
 
 static const struct regmap_config rt286_regmap = {
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c
index f80cfe4..5555864 100644
--- a/sound/soc/codecs/rt298.c
+++ b/sound/soc/codecs/rt298.c
@@ -1095,12 +1095,14 @@
 	.resume = rt298_resume,
 	.set_bias_level = rt298_set_bias_level,
 	.idle_bias_off = true,
-	.controls = rt298_snd_controls,
-	.num_controls = ARRAY_SIZE(rt298_snd_controls),
-	.dapm_widgets = rt298_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(rt298_dapm_widgets),
-	.dapm_routes = rt298_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(rt298_dapm_routes),
+	.component_driver = {
+		.controls		= rt298_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt298_snd_controls),
+		.dapm_widgets		= rt298_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt298_dapm_widgets),
+		.dapm_routes		= rt298_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt298_dapm_routes),
+	},
 };
 
 static const struct regmap_config rt298_regmap = {
diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c
index 77ff8eb..09103aa 100644
--- a/sound/soc/codecs/rt5514-spi.c
+++ b/sound/soc/codecs/rt5514-spi.c
@@ -236,7 +236,7 @@
 	return bytes_to_frames(runtime, rt5514_dsp->dma_offset);
 }
 
-static struct snd_pcm_ops rt5514_spi_pcm_ops = {
+static const struct snd_pcm_ops rt5514_spi_pcm_ops = {
 	.open		= rt5514_spi_pcm_open,
 	.hw_params	= rt5514_spi_hw_params,
 	.hw_free	= rt5514_spi_hw_free,
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
index 7162f05..f24b7cf 100644
--- a/sound/soc/codecs/rt5514.c
+++ b/sound/soc/codecs/rt5514.c
@@ -278,7 +278,7 @@
 	8, 8, TLV_DB_SCALE_ITEM(1700, 0, 0)
 );
 
-static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0);
 
 static int rt5514_dsp_voice_wake_up_get(struct snd_kcontrol *kcontrol,
 		struct snd_ctl_elem_value *ucontrol)
@@ -352,10 +352,10 @@
 	SOC_DOUBLE_TLV("MIC Boost Volume", RT5514_ANA_CTRL_MICBST,
 		RT5514_SEL_BSTL_SFT, RT5514_SEL_BSTR_SFT, 8, 0, bst_tlv),
 	SOC_DOUBLE_R_TLV("ADC1 Capture Volume", RT5514_DOWNFILTER0_CTRL1,
-		RT5514_DOWNFILTER0_CTRL2, RT5514_AD_GAIN_SFT, 127, 0,
+		RT5514_DOWNFILTER0_CTRL2, RT5514_AD_GAIN_SFT, 63, 0,
 		adc_vol_tlv),
 	SOC_DOUBLE_R_TLV("ADC2 Capture Volume", RT5514_DOWNFILTER1_CTRL1,
-		RT5514_DOWNFILTER1_CTRL2, RT5514_AD_GAIN_SFT, 127, 0,
+		RT5514_DOWNFILTER1_CTRL2, RT5514_AD_GAIN_SFT, 63, 0,
 		adc_vol_tlv),
 	SOC_SINGLE_EXT("DSP Voice Wake Up", SND_SOC_NOPM, 0, 1, 0,
 		rt5514_dsp_voice_wake_up_get, rt5514_dsp_voice_wake_up_put),
@@ -1023,12 +1023,14 @@
 	.probe = rt5514_probe,
 	.idle_bias_off = true,
 	.set_bias_level = rt5514_set_bias_level,
-	.controls = rt5514_snd_controls,
-	.num_controls = ARRAY_SIZE(rt5514_snd_controls),
-	.dapm_widgets = rt5514_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(rt5514_dapm_widgets),
-	.dapm_routes = rt5514_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(rt5514_dapm_routes),
+	.component_driver = {
+		.controls		= rt5514_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt5514_snd_controls),
+		.dapm_widgets		= rt5514_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt5514_dapm_widgets),
+		.dapm_routes		= rt5514_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt5514_dapm_routes),
+	},
 };
 
 static const struct regmap_config rt5514_i2c_regmap = {
diff --git a/sound/soc/codecs/rt5514.h b/sound/soc/codecs/rt5514.h
index 68883c6..229de0e 100644
--- a/sound/soc/codecs/rt5514.h
+++ b/sound/soc/codecs/rt5514.h
@@ -196,8 +196,8 @@
 #define RT5514_AD_AD_MIX_BIT			10
 #define RT5514_AD_AD_MUTE			(0x1 << 7)
 #define RT5514_AD_AD_MUTE_BIT			7
-#define RT5514_AD_GAIN_MASK			(0x7f << 0)
-#define RT5514_AD_GAIN_SFT			0
+#define RT5514_AD_GAIN_MASK			(0x3f << 1)
+#define RT5514_AD_GAIN_SFT			1
 
 /*  RT5514_ANA_CTRL_MICBST (0x2220) */
 #define RT5514_SEL_BSTL_MASK			(0xf << 4)
diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c
index f527b5b..d1f273b 100644
--- a/sound/soc/codecs/rt5616.c
+++ b/sound/soc/codecs/rt5616.c
@@ -294,8 +294,7 @@
 static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
 
 /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
-static unsigned int bst_tlv[] = {
-	TLV_DB_RANGE_HEAD(7),
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(bst_tlv,
 	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
 	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
 	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
@@ -303,7 +302,7 @@
 	6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
 	7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
 	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
-};
+);
 
 static const struct snd_kcontrol_new rt5616_snd_controls[] = {
 	/* Headphone Output Volume */
@@ -1267,14 +1266,14 @@
 #define RT5616_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
-struct snd_soc_dai_ops rt5616_aif_dai_ops = {
+static struct snd_soc_dai_ops rt5616_aif_dai_ops = {
 	.hw_params = rt5616_hw_params,
 	.set_fmt = rt5616_set_dai_fmt,
 	.set_sysclk = rt5616_set_dai_sysclk,
 	.set_pll = rt5616_set_dai_pll,
 };
 
-struct snd_soc_dai_driver rt5616_dai[] = {
+static struct snd_soc_dai_driver rt5616_dai[] = {
 	{
 		.name = "rt5616-aif1",
 		.id = RT5616_AIF1,
@@ -1302,12 +1301,14 @@
 	.resume = rt5616_resume,
 	.set_bias_level = rt5616_set_bias_level,
 	.idle_bias_off = true,
-	.controls = rt5616_snd_controls,
-	.num_controls = ARRAY_SIZE(rt5616_snd_controls),
-	.dapm_widgets = rt5616_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(rt5616_dapm_widgets),
-	.dapm_routes = rt5616_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(rt5616_dapm_routes),
+	.component_driver = {
+		.controls		= rt5616_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt5616_snd_controls),
+		.dapm_widgets		= rt5616_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt5616_dapm_widgets),
+		.dapm_routes		= rt5616_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt5616_dapm_routes),
+	},
 };
 
 static const struct regmap_config rt5616_regmap = {
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
index 1be2bab..0e41808 100644
--- a/sound/soc/codecs/rt5631.c
+++ b/sound/soc/codecs/rt5631.c
@@ -1657,12 +1657,14 @@
 	.probe = rt5631_probe,
 	.set_bias_level = rt5631_set_bias_level,
 	.suspend_bias_off = true,
-	.controls = rt5631_snd_controls,
-	.num_controls = ARRAY_SIZE(rt5631_snd_controls),
-	.dapm_widgets = rt5631_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(rt5631_dapm_widgets),
-	.dapm_routes = rt5631_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(rt5631_dapm_routes),
+	.component_driver = {
+		.controls		= rt5631_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt5631_snd_controls),
+		.dapm_widgets		= rt5631_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt5631_dapm_widgets),
+		.dapm_routes		= rt5631_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt5631_dapm_routes),
+	},
 };
 
 static const struct i2c_device_id rt5631_i2c_id[] = {
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 09e8988..3cc1135 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -1870,6 +1870,9 @@
 	case RT5640_SCLK_S_PLL1:
 		reg_val |= RT5640_SCLK_SRC_PLL1;
 		break;
+	case RT5640_SCLK_S_RCCLK:
+		reg_val |= RT5640_SCLK_SRC_RCCLK;
+		break;
 	default:
 		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
 		return -EINVAL;
@@ -2261,12 +2264,14 @@
 	.resume = rt5640_resume,
 	.set_bias_level = rt5640_set_bias_level,
 	.idle_bias_off = true,
-	.controls = rt5640_snd_controls,
-	.num_controls = ARRAY_SIZE(rt5640_snd_controls),
-	.dapm_widgets = rt5640_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(rt5640_dapm_widgets),
-	.dapm_routes = rt5640_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(rt5640_dapm_routes),
+	.component_driver = {
+		.controls		= rt5640_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt5640_snd_controls),
+		.dapm_widgets		= rt5640_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt5640_dapm_widgets),
+		.dapm_routes		= rt5640_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt5640_dapm_routes),
+	},
 };
 
 static const struct regmap_config rt5640_regmap = {
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h
index 58b664b..90c8871 100644
--- a/sound/soc/codecs/rt5640.h
+++ b/sound/soc/codecs/rt5640.h
@@ -984,6 +984,7 @@
 #define RT5640_SCLK_SRC_SFT			14
 #define RT5640_SCLK_SRC_MCLK			(0x0 << 14)
 #define RT5640_SCLK_SRC_PLL1			(0x1 << 14)
+#define RT5640_SCLK_SRC_RCCLK			(0x2 << 14)
 #define RT5640_PLL1_SRC_MASK			(0x3 << 12)
 #define RT5640_PLL1_SRC_SFT			12
 #define RT5640_PLL1_SRC_MCLK			(0x0 << 12)
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 490bfe6..10c2a56 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -3484,12 +3484,14 @@
 	.resume = rt5645_resume,
 	.set_bias_level = rt5645_set_bias_level,
 	.idle_bias_off = true,
-	.controls = rt5645_snd_controls,
-	.num_controls = ARRAY_SIZE(rt5645_snd_controls),
-	.dapm_widgets = rt5645_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(rt5645_dapm_widgets),
-	.dapm_routes = rt5645_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(rt5645_dapm_routes),
+	.component_driver = {
+		.controls		= rt5645_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt5645_snd_controls),
+		.dapm_widgets		= rt5645_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt5645_dapm_widgets),
+		.dapm_routes		= rt5645_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt5645_dapm_routes),
+	},
 };
 
 static const struct regmap_config rt5645_regmap = {
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
index 7a61970..f5d3415 100644
--- a/sound/soc/codecs/rt5651.c
+++ b/sound/soc/codecs/rt5651.c
@@ -1712,12 +1712,14 @@
 	.resume = rt5651_resume,
 	.set_bias_level = rt5651_set_bias_level,
 	.idle_bias_off = true,
-	.controls = rt5651_snd_controls,
-	.num_controls = ARRAY_SIZE(rt5651_snd_controls),
-	.dapm_widgets = rt5651_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(rt5651_dapm_widgets),
-	.dapm_routes = rt5651_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(rt5651_dapm_routes),
+	.component_driver = {
+		.controls		= rt5651_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt5651_snd_controls),
+		.dapm_widgets		= rt5651_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt5651_dapm_widgets),
+		.dapm_routes		= rt5651_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt5651_dapm_routes),
+	},
 };
 
 static const struct regmap_config rt5651_regmap = {
diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c
index 1b30914..db54550 100644
--- a/sound/soc/codecs/rt5659.c
+++ b/sound/soc/codecs/rt5659.c
@@ -9,6 +9,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/clk.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
@@ -3565,7 +3566,9 @@
 static int rt5659_set_bias_level(struct snd_soc_codec *codec,
 			enum snd_soc_bias_level level)
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+	int ret;
 
 	switch (level) {
 	case SND_SOC_BIAS_PREPARE:
@@ -3582,6 +3585,17 @@
 			RT5659_PWR_FV1 | RT5659_PWR_FV2);
 		break;
 
+	case SND_SOC_BIAS_STANDBY:
+		if (dapm->bias_level == SND_SOC_BIAS_OFF) {
+			ret = clk_prepare_enable(rt5659->mclk);
+			if (ret) {
+				dev_err(codec->dev,
+					"failed to enable MCLK: %d\n", ret);
+				return ret;
+			}
+		}
+		break;
+
 	case SND_SOC_BIAS_OFF:
 		regmap_update_bits(rt5659->regmap, RT5659_PWR_DIG_1,
 			RT5659_PWR_LDO, 0);
@@ -3591,6 +3605,7 @@
 			RT5659_PWR_MB | RT5659_PWR_VREF2);
 		regmap_update_bits(rt5659->regmap, RT5659_DIG_MISC,
 			RT5659_DIG_GATE_CTRL, 0);
+		clk_disable_unprepare(rt5659->mclk);
 		break;
 
 	default:
@@ -3722,12 +3737,14 @@
 	.resume = rt5659_resume,
 	.set_bias_level = rt5659_set_bias_level,
 	.idle_bias_off = true,
-	.controls = rt5659_snd_controls,
-	.num_controls = ARRAY_SIZE(rt5659_snd_controls),
-	.dapm_widgets = rt5659_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(rt5659_dapm_widgets),
-	.dapm_routes = rt5659_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(rt5659_dapm_routes),
+	.component_driver = {
+		.controls		= rt5659_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt5659_snd_controls),
+		.dapm_widgets		= rt5659_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt5659_dapm_widgets),
+		.dapm_routes		= rt5659_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt5659_dapm_routes),
+	},
 };
 
 
@@ -4020,6 +4037,15 @@
 
 	regmap_write(rt5659->regmap, RT5659_RESET, 0);
 
+	/* Check if MCLK provided */
+	rt5659->mclk = devm_clk_get(&i2c->dev, "mclk");
+	if (IS_ERR(rt5659->mclk)) {
+		if (PTR_ERR(rt5659->mclk) != -ENOENT)
+			return PTR_ERR(rt5659->mclk);
+		/* Otherwise mark the mclk pointer to NULL */
+		rt5659->mclk = NULL;
+	}
+
 	rt5659_calibrate(rt5659);
 
 	/* line in diff mode*/
@@ -4163,6 +4189,9 @@
 		if (ret)
 			dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
 
+		/* Enable IRQ output for GPIO1 pin any way */
+		regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+				   RT5659_GP1_PIN_MASK, RT5659_GP1_PIN_IRQ);
 	}
 
 	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5659,
diff --git a/sound/soc/codecs/rt5659.h b/sound/soc/codecs/rt5659.h
index d31c9e5..8f1aeef 100644
--- a/sound/soc/codecs/rt5659.h
+++ b/sound/soc/codecs/rt5659.h
@@ -180,9 +180,9 @@
 #define RT5659_IRQ_CTRL_1			0x00b6
 #define RT5659_IRQ_CTRL_2			0x00b7
 #define RT5659_IRQ_CTRL_3			0x00b8
-#define RT5659_IRQ_CTRL_4			0x00b9
-#define RT5659_IRQ_CTRL_5			0x00ba
-#define RT5659_IRQ_CTRL_6			0x00bb
+#define RT5659_IRQ_CTRL_4			0x00ba
+#define RT5659_IRQ_CTRL_5			0x00bb
+#define RT5659_IRQ_CTRL_6			0x00bc
 #define RT5659_INT_ST_1				0x00be
 #define RT5659_INT_ST_2				0x00bf
 #define RT5659_GPIO_CTRL_1			0x00c0
@@ -1796,6 +1796,7 @@
 	struct gpio_desc *gpiod_reset;
 	struct snd_soc_jack *hs_jack;
 	struct delayed_work jack_detect_work;
+	struct clk *mclk;
 
 	int sysclk;
 	int sysclk_src;
diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c
new file mode 100644
index 0000000..9f0933c
--- /dev/null
+++ b/sound/soc/codecs/rt5660.c
@@ -0,0 +1,1353 @@
+/*
+ * rt5660.c  --  RT5660 ALSA SoC audio codec driver
+ *
+ * Copyright 2016 Realtek Semiconductor Corp.
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.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 "rl6231.h"
+#include "rt5660.h"
+
+#define RT5660_DEVICE_ID 0x6338
+
+#define RT5660_PR_RANGE_BASE (0xff + 1)
+#define RT5660_PR_SPACING 0x100
+
+#define RT5660_PR_BASE (RT5660_PR_RANGE_BASE + (0 * RT5660_PR_SPACING))
+
+static const struct regmap_range_cfg rt5660_ranges[] = {
+	{ .name = "PR", .range_min = RT5660_PR_BASE,
+	  .range_max = RT5660_PR_BASE + 0xf3,
+	  .selector_reg = RT5660_PRIV_INDEX,
+	  .selector_mask = 0xff,
+	  .selector_shift = 0x0,
+	  .window_start = RT5660_PRIV_DATA,
+	  .window_len = 0x1, },
+};
+
+static const struct reg_sequence rt5660_patch[] = {
+	{ RT5660_ALC_PGA_CTRL2,		0x44c3 },
+	{ RT5660_PR_BASE + 0x3d,	0x2600 },
+};
+
+static const struct reg_default rt5660_reg[] = {
+	{ 0x00, 0x0000 },
+	{ 0x01, 0xc800 },
+	{ 0x02, 0xc8c8 },
+	{ 0x0d, 0x1010 },
+	{ 0x0e, 0x1010 },
+	{ 0x19, 0xafaf },
+	{ 0x1c, 0x2f2f },
+	{ 0x1e, 0x0000 },
+	{ 0x27, 0x6060 },
+	{ 0x29, 0x8080 },
+	{ 0x2a, 0x4242 },
+	{ 0x2f, 0x0000 },
+	{ 0x3b, 0x0000 },
+	{ 0x3c, 0x007f },
+	{ 0x3d, 0x0000 },
+	{ 0x3e, 0x007f },
+	{ 0x45, 0xe000 },
+	{ 0x46, 0x003e },
+	{ 0x48, 0xf800 },
+	{ 0x4a, 0x0004 },
+	{ 0x4d, 0x0000 },
+	{ 0x4e, 0x0000 },
+	{ 0x4f, 0x01ff },
+	{ 0x50, 0x0000 },
+	{ 0x51, 0x0000 },
+	{ 0x52, 0x01ff },
+	{ 0x61, 0x0000 },
+	{ 0x62, 0x0000 },
+	{ 0x63, 0x00c0 },
+	{ 0x64, 0x0000 },
+	{ 0x65, 0x0000 },
+	{ 0x66, 0x0000 },
+	{ 0x70, 0x8000 },
+	{ 0x73, 0x7000 },
+	{ 0x74, 0x3c00 },
+	{ 0x75, 0x2800 },
+	{ 0x80, 0x0000 },
+	{ 0x81, 0x0000 },
+	{ 0x82, 0x0000 },
+	{ 0x8c, 0x0228 },
+	{ 0x8d, 0xa000 },
+	{ 0x8e, 0x0000 },
+	{ 0x92, 0x0000 },
+	{ 0x93, 0x3000 },
+	{ 0xa1, 0x0059 },
+	{ 0xa2, 0x0001 },
+	{ 0xa3, 0x5c80 },
+	{ 0xa4, 0x0146 },
+	{ 0xa5, 0x1f1f },
+	{ 0xa6, 0x78c6 },
+	{ 0xa7, 0xe5ec },
+	{ 0xa8, 0xba61 },
+	{ 0xa9, 0x3c78 },
+	{ 0xaa, 0x8ae2 },
+	{ 0xab, 0xe5ec },
+	{ 0xac, 0xc600 },
+	{ 0xad, 0xba61 },
+	{ 0xae, 0x17ed },
+	{ 0xb0, 0x2080 },
+	{ 0xb1, 0x0000 },
+	{ 0xb3, 0x001f },
+	{ 0xb4, 0x020c },
+	{ 0xb5, 0x1f00 },
+	{ 0xb6, 0x0000 },
+	{ 0xb7, 0x4000 },
+	{ 0xbb, 0x0000 },
+	{ 0xbd, 0x0000 },
+	{ 0xbe, 0x0000 },
+	{ 0xbf, 0x0100 },
+	{ 0xc0, 0x0000 },
+	{ 0xc2, 0x0000 },
+	{ 0xd3, 0xa220 },
+	{ 0xd9, 0x0809 },
+	{ 0xda, 0x0000 },
+	{ 0xe0, 0x8000 },
+	{ 0xe1, 0x0200 },
+	{ 0xe2, 0x8000 },
+	{ 0xe3, 0x0200 },
+	{ 0xe4, 0x0f20 },
+	{ 0xe5, 0x001f },
+	{ 0xe6, 0x020c },
+	{ 0xe7, 0x1f00 },
+	{ 0xe8, 0x0000 },
+	{ 0xe9, 0x4000 },
+	{ 0xea, 0x00a6 },
+	{ 0xeb, 0x04c3 },
+	{ 0xec, 0x27c8 },
+	{ 0xed, 0x7418 },
+	{ 0xee, 0xbf50 },
+	{ 0xef, 0x0045 },
+	{ 0xf0, 0x0007 },
+	{ 0xfa, 0x0000 },
+	{ 0xfd, 0x0000 },
+	{ 0xfe, 0x10ec },
+	{ 0xff, 0x6338 },
+};
+
+static bool rt5660_volatile_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt5660_ranges); i++)
+		if ((reg >= rt5660_ranges[i].window_start &&
+		     reg <= rt5660_ranges[i].window_start +
+		     rt5660_ranges[i].window_len) ||
+		    (reg >= rt5660_ranges[i].range_min &&
+		     reg <= rt5660_ranges[i].range_max))
+			return true;
+
+	switch (reg) {
+	case RT5660_RESET:
+	case RT5660_PRIV_DATA:
+	case RT5660_EQ_CTRL1:
+	case RT5660_IRQ_CTRL2:
+	case RT5660_INT_IRQ_ST:
+	case RT5660_VENDOR_ID:
+	case RT5660_VENDOR_ID1:
+	case RT5660_VENDOR_ID2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5660_readable_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt5660_ranges); i++)
+		if ((reg >= rt5660_ranges[i].window_start &&
+		     reg <= rt5660_ranges[i].window_start +
+		     rt5660_ranges[i].window_len) ||
+		    (reg >= rt5660_ranges[i].range_min &&
+		     reg <= rt5660_ranges[i].range_max))
+			return true;
+
+	switch (reg) {
+	case RT5660_RESET:
+	case RT5660_SPK_VOL:
+	case RT5660_LOUT_VOL:
+	case RT5660_IN1_IN2:
+	case RT5660_IN3_IN4:
+	case RT5660_DAC1_DIG_VOL:
+	case RT5660_STO1_ADC_DIG_VOL:
+	case RT5660_ADC_BST_VOL1:
+	case RT5660_STO1_ADC_MIXER:
+	case RT5660_AD_DA_MIXER:
+	case RT5660_STO_DAC_MIXER:
+	case RT5660_DIG_INF1_DATA:
+	case RT5660_REC_L1_MIXER:
+	case RT5660_REC_L2_MIXER:
+	case RT5660_REC_R1_MIXER:
+	case RT5660_REC_R2_MIXER:
+	case RT5660_LOUT_MIXER:
+	case RT5660_SPK_MIXER:
+	case RT5660_SPO_MIXER:
+	case RT5660_SPO_CLSD_RATIO:
+	case RT5660_OUT_L_GAIN1:
+	case RT5660_OUT_L_GAIN2:
+	case RT5660_OUT_L1_MIXER:
+	case RT5660_OUT_R_GAIN1:
+	case RT5660_OUT_R_GAIN2:
+	case RT5660_OUT_R1_MIXER:
+	case RT5660_PWR_DIG1:
+	case RT5660_PWR_DIG2:
+	case RT5660_PWR_ANLG1:
+	case RT5660_PWR_ANLG2:
+	case RT5660_PWR_MIXER:
+	case RT5660_PWR_VOL:
+	case RT5660_PRIV_INDEX:
+	case RT5660_PRIV_DATA:
+	case RT5660_I2S1_SDP:
+	case RT5660_ADDA_CLK1:
+	case RT5660_ADDA_CLK2:
+	case RT5660_DMIC_CTRL1:
+	case RT5660_GLB_CLK:
+	case RT5660_PLL_CTRL1:
+	case RT5660_PLL_CTRL2:
+	case RT5660_CLSD_AMP_OC_CTRL:
+	case RT5660_CLSD_AMP_CTRL:
+	case RT5660_LOUT_AMP_CTRL:
+	case RT5660_SPK_AMP_SPKVDD:
+	case RT5660_MICBIAS:
+	case RT5660_CLSD_OUT_CTRL1:
+	case RT5660_CLSD_OUT_CTRL2:
+	case RT5660_DIPOLE_MIC_CTRL1:
+	case RT5660_DIPOLE_MIC_CTRL2:
+	case RT5660_DIPOLE_MIC_CTRL3:
+	case RT5660_DIPOLE_MIC_CTRL4:
+	case RT5660_DIPOLE_MIC_CTRL5:
+	case RT5660_DIPOLE_MIC_CTRL6:
+	case RT5660_DIPOLE_MIC_CTRL7:
+	case RT5660_DIPOLE_MIC_CTRL8:
+	case RT5660_DIPOLE_MIC_CTRL9:
+	case RT5660_DIPOLE_MIC_CTRL10:
+	case RT5660_DIPOLE_MIC_CTRL11:
+	case RT5660_DIPOLE_MIC_CTRL12:
+	case RT5660_EQ_CTRL1:
+	case RT5660_EQ_CTRL2:
+	case RT5660_DRC_AGC_CTRL1:
+	case RT5660_DRC_AGC_CTRL2:
+	case RT5660_DRC_AGC_CTRL3:
+	case RT5660_DRC_AGC_CTRL4:
+	case RT5660_DRC_AGC_CTRL5:
+	case RT5660_JD_CTRL:
+	case RT5660_IRQ_CTRL1:
+	case RT5660_IRQ_CTRL2:
+	case RT5660_INT_IRQ_ST:
+	case RT5660_GPIO_CTRL1:
+	case RT5660_GPIO_CTRL2:
+	case RT5660_WIND_FILTER_CTRL1:
+	case RT5660_SV_ZCD1:
+	case RT5660_SV_ZCD2:
+	case RT5660_DRC1_LM_CTRL1:
+	case RT5660_DRC1_LM_CTRL2:
+	case RT5660_DRC2_LM_CTRL1:
+	case RT5660_DRC2_LM_CTRL2:
+	case RT5660_MULTI_DRC_CTRL:
+	case RT5660_DRC2_CTRL1:
+	case RT5660_DRC2_CTRL2:
+	case RT5660_DRC2_CTRL3:
+	case RT5660_DRC2_CTRL4:
+	case RT5660_DRC2_CTRL5:
+	case RT5660_ALC_PGA_CTRL1:
+	case RT5660_ALC_PGA_CTRL2:
+	case RT5660_ALC_PGA_CTRL3:
+	case RT5660_ALC_PGA_CTRL4:
+	case RT5660_ALC_PGA_CTRL5:
+	case RT5660_ALC_PGA_CTRL6:
+	case RT5660_ALC_PGA_CTRL7:
+	case RT5660_GEN_CTRL1:
+	case RT5660_GEN_CTRL2:
+	case RT5660_GEN_CTRL3:
+	case RT5660_VENDOR_ID:
+	case RT5660_VENDOR_ID1:
+	case RT5660_VENDOR_ID2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(rt5660_out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(rt5660_dac_vol_tlv, -6525, 75, 0);
+static const DECLARE_TLV_DB_SCALE(rt5660_adc_vol_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(rt5660_adc_bst_tlv, 0, 1200, 0);
+static const DECLARE_TLV_DB_SCALE(rt5660_bst_tlv, -1200, 75, 0);
+
+static const struct snd_kcontrol_new rt5660_snd_controls[] = {
+	/* Speaker Output Volume */
+	SOC_SINGLE("Speaker Playback Switch", RT5660_SPK_VOL, RT5660_L_MUTE_SFT,
+		1, 1),
+	SOC_SINGLE_TLV("Speaker Playback Volume", RT5660_SPK_VOL,
+		RT5660_L_VOL_SFT, 39, 1, rt5660_out_vol_tlv),
+
+	/* OUTPUT Control */
+	SOC_DOUBLE("OUT Playback Switch", RT5660_LOUT_VOL, RT5660_L_MUTE_SFT,
+		RT5660_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("OUT Playback Volume", RT5660_LOUT_VOL, RT5660_L_VOL_SFT,
+		RT5660_R_VOL_SFT, 39, 1, rt5660_out_vol_tlv),
+
+	/* DAC Digital Volume */
+	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5660_DAC1_DIG_VOL,
+		RT5660_DAC_L1_VOL_SFT, RT5660_DAC_R1_VOL_SFT, 87, 0,
+		rt5660_dac_vol_tlv),
+
+	/* IN1/IN2/IN3 Control */
+	SOC_SINGLE_TLV("IN1 Boost Volume", RT5660_IN1_IN2, RT5660_BST_SFT1, 69,
+		0, rt5660_bst_tlv),
+	SOC_SINGLE_TLV("IN2 Boost Volume", RT5660_IN1_IN2, RT5660_BST_SFT2, 69,
+		0, rt5660_bst_tlv),
+	SOC_SINGLE_TLV("IN3 Boost Volume", RT5660_IN3_IN4, RT5660_BST_SFT3, 69,
+		0, rt5660_bst_tlv),
+
+	/* ADC Digital Volume Control */
+	SOC_DOUBLE("ADC Capture Switch", RT5660_STO1_ADC_DIG_VOL,
+		RT5660_L_MUTE_SFT, RT5660_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("ADC Capture Volume", RT5660_STO1_ADC_DIG_VOL,
+		RT5660_ADC_L_VOL_SFT, RT5660_ADC_R_VOL_SFT, 63, 0,
+		rt5660_adc_vol_tlv),
+
+	/* ADC Boost Volume Control */
+	SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5660_ADC_BST_VOL1,
+		RT5660_STO1_ADC_L_BST_SFT, RT5660_STO1_ADC_R_BST_SFT, 3, 0,
+		rt5660_adc_bst_tlv),
+};
+
+/**
+ * rt5660_set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ */
+static int rt5660_set_dmic_clk(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+	int idx, rate;
+
+	rate = rt5660->sysclk / rl6231_get_pre_div(rt5660->regmap,
+		RT5660_ADDA_CLK1, RT5660_I2S_PD1_SFT);
+	idx = rl6231_calc_dmic_clk(rate);
+	if (idx < 0)
+		dev_err(codec->dev, "Failed to set DMIC clock\n");
+	else
+		snd_soc_update_bits(codec, RT5660_DMIC_CTRL1,
+			RT5660_DMIC_CLK_MASK, idx << RT5660_DMIC_CLK_SFT);
+
+	return idx;
+}
+
+static int rt5660_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	unsigned int val;
+
+	val = snd_soc_read(codec, RT5660_GLB_CLK);
+	val &= RT5660_SCLK_SRC_MASK;
+	if (val == RT5660_SCLK_SRC_PLL1)
+		return 1;
+	else
+		return 0;
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5660_sto1_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5660_STO1_ADC_MIXER,
+			RT5660_M_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5660_STO1_ADC_MIXER,
+			RT5660_M_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_sto1_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5660_STO1_ADC_MIXER,
+			RT5660_M_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5660_STO1_ADC_MIXER,
+			RT5660_M_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5660_AD_DA_MIXER,
+			RT5660_M_ADCMIX_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5660_AD_DA_MIXER,
+			RT5660_M_DAC1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5660_AD_DA_MIXER,
+			RT5660_M_ADCMIX_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5660_AD_DA_MIXER,
+			RT5660_M_DAC1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_sto_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5660_STO_DAC_MIXER,
+			RT5660_M_DAC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5660_STO_DAC_MIXER,
+			RT5660_M_DAC_R1_STO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_sto_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5660_STO_DAC_MIXER,
+			RT5660_M_DAC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5660_STO_DAC_MIXER,
+			RT5660_M_DAC_L1_STO_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5660_rec_l_mix[] = {
+	SOC_DAPM_SINGLE("BST3 Switch", RT5660_REC_L2_MIXER,
+			RT5660_M_BST3_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5660_REC_L2_MIXER,
+			RT5660_M_BST2_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5660_REC_L2_MIXER,
+			RT5660_M_BST1_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUT MIXL Switch", RT5660_REC_L2_MIXER,
+			RT5660_M_OM_L_RM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_rec_r_mix[] = {
+	SOC_DAPM_SINGLE("BST3 Switch", RT5660_REC_R2_MIXER,
+			RT5660_M_BST3_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5660_REC_R2_MIXER,
+			RT5660_M_BST2_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5660_REC_R2_MIXER,
+			RT5660_M_BST1_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUT MIXR Switch", RT5660_REC_R2_MIXER,
+			RT5660_M_OM_R_RM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_spk_mix[] = {
+	SOC_DAPM_SINGLE("BST3 Switch", RT5660_SPK_MIXER,
+			RT5660_M_BST3_SM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5660_SPK_MIXER,
+			RT5660_M_BST1_SM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DACL Switch", RT5660_SPK_MIXER,
+			RT5660_M_DACL_SM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DACR Switch", RT5660_SPK_MIXER,
+			RT5660_M_DACR_SM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTMIXL Switch", RT5660_SPK_MIXER,
+			RT5660_M_OM_L_SM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_out_l_mix[] = {
+	SOC_DAPM_SINGLE("BST3 Switch", RT5660_OUT_L1_MIXER,
+			RT5660_M_BST3_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5660_OUT_L1_MIXER,
+			RT5660_M_BST2_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5660_OUT_L1_MIXER,
+			RT5660_M_BST1_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("RECMIXL Switch", RT5660_OUT_L1_MIXER,
+			RT5660_M_RM_L_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DACR Switch", RT5660_OUT_L1_MIXER,
+			RT5660_M_DAC_R_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DACL Switch", RT5660_OUT_L1_MIXER,
+			RT5660_M_DAC_L_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_out_r_mix[] = {
+	SOC_DAPM_SINGLE("BST2 Switch", RT5660_OUT_R1_MIXER,
+			RT5660_M_BST2_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5660_OUT_R1_MIXER,
+			RT5660_M_BST1_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("RECMIXR Switch", RT5660_OUT_R1_MIXER,
+			RT5660_M_RM_R_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DACR Switch", RT5660_OUT_R1_MIXER,
+			RT5660_M_DAC_R_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DACL Switch", RT5660_OUT_R1_MIXER,
+			RT5660_M_DAC_L_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_spo_mix[] = {
+	SOC_DAPM_SINGLE("DACR Switch", RT5660_SPO_MIXER,
+			RT5660_M_DAC_R_SPM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DACL Switch", RT5660_SPO_MIXER,
+			RT5660_M_DAC_L_SPM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("SPKVOL Switch", RT5660_SPO_MIXER,
+			RT5660_M_SV_SPM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5660_SPO_MIXER,
+			RT5660_M_BST1_SPM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_lout_mix[] = {
+	SOC_DAPM_SINGLE("DAC Switch", RT5660_LOUT_MIXER,
+			RT5660_M_DAC1_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTMIX Switch", RT5660_LOUT_MIXER,
+			RT5660_M_LOVOL_LM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new spk_vol_control =
+	SOC_DAPM_SINGLE("Switch", RT5660_SPK_VOL,
+		RT5660_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_l_vol_control =
+	SOC_DAPM_SINGLE("Switch", RT5660_LOUT_VOL,
+		RT5660_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_r_vol_control =
+	SOC_DAPM_SINGLE("Switch", RT5660_LOUT_VOL,
+		RT5660_VOL_R_SFT, 1, 1);
+
+/* Interface data select */
+static const char * const rt5660_data_select[] = {
+	"L/R", "R/L", "L/L", "R/R"
+};
+
+static const SOC_ENUM_SINGLE_DECL(rt5660_if1_dac_enum,
+	RT5660_DIG_INF1_DATA, RT5660_IF1_DAC_IN_SFT, rt5660_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5660_if1_adc_enum,
+	RT5660_DIG_INF1_DATA, RT5660_IF1_ADC_IN_SFT, rt5660_data_select);
+
+static const struct snd_kcontrol_new rt5660_if1_dac_swap_mux =
+	SOC_DAPM_ENUM("IF1 DAC Swap Source", rt5660_if1_dac_enum);
+
+static const struct snd_kcontrol_new rt5660_if1_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 ADC Swap Source", rt5660_if1_adc_enum);
+
+static int rt5660_lout_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec, RT5660_LOUT_AMP_CTRL,
+			RT5660_LOUT_CO_MASK | RT5660_LOUT_CB_MASK,
+			RT5660_LOUT_CO_EN | RT5660_LOUT_CB_PU);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, RT5660_LOUT_AMP_CTRL,
+			RT5660_LOUT_CO_MASK | RT5660_LOUT_CB_MASK,
+			RT5660_LOUT_CO_DIS | RT5660_LOUT_CB_PD);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5660_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("LDO2", RT5660_PWR_ANLG1,
+		RT5660_PWR_LDO2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL1", RT5660_PWR_ANLG2,
+		RT5660_PWR_PLL_BIT, 0, NULL, 0),
+
+	/* MICBIAS */
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5660_PWR_ANLG2,
+			RT5660_PWR_MB1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5660_PWR_ANLG2,
+			RT5660_PWR_MB2_BIT, 0, NULL, 0),
+
+	/* Input Side */
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("DMIC L1"),
+	SND_SOC_DAPM_INPUT("DMIC R1"),
+
+	SND_SOC_DAPM_INPUT("IN1P"),
+	SND_SOC_DAPM_INPUT("IN1N"),
+	SND_SOC_DAPM_INPUT("IN2P"),
+	SND_SOC_DAPM_INPUT("IN3P"),
+	SND_SOC_DAPM_INPUT("IN3N"),
+
+	SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+		rt5660_set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SUPPLY("DMIC Power", RT5660_DMIC_CTRL1,
+		RT5660_DMIC_1_EN_SFT, 0, NULL, 0),
+
+	/* Boost */
+	SND_SOC_DAPM_PGA("BST1", RT5660_PWR_ANLG2, RT5660_PWR_BST1_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_PGA("BST2", RT5660_PWR_ANLG2, RT5660_PWR_BST2_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_PGA("BST3", RT5660_PWR_ANLG2, RT5660_PWR_BST3_BIT, 0,
+		NULL, 0),
+
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIXL", RT5660_PWR_MIXER, RT5660_PWR_RM_L_BIT,
+			0, rt5660_rec_l_mix, ARRAY_SIZE(rt5660_rec_l_mix)),
+	SND_SOC_DAPM_MIXER("RECMIXR", RT5660_PWR_MIXER, RT5660_PWR_RM_R_BIT,
+			0, rt5660_rec_r_mix, ARRAY_SIZE(rt5660_rec_r_mix)),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_SUPPLY("ADC L power", RT5660_PWR_DIG1,
+			RT5660_PWR_ADC_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC R power", RT5660_PWR_DIG1,
+			RT5660_PWR_ADC_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC clock", RT5660_PR_BASE + RT5660_CHOP_DAC_ADC,
+			12, 0, NULL, 0),
+
+	/* ADC Mixer */
+	SND_SOC_DAPM_SUPPLY("adc stereo1 filter", RT5660_PWR_DIG2,
+		RT5660_PWR_ADC_S1F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Sto1 ADC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5660_sto1_adc_l_mix, ARRAY_SIZE(rt5660_sto1_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Sto1 ADC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5660_sto1_adc_r_mix, ARRAY_SIZE(rt5660_sto1_adc_r_mix)),
+
+	/* ADC */
+	SND_SOC_DAPM_ADC("Stereo1 ADC MIXL", NULL, RT5660_STO1_ADC_DIG_VOL,
+		RT5660_L_MUTE_SFT, 1),
+	SND_SOC_DAPM_ADC("Stereo1 ADC MIXR", NULL, RT5660_STO1_ADC_DIG_VOL,
+		RT5660_R_MUTE_SFT, 1),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_SUPPLY("I2S1", RT5660_PWR_DIG1, RT5660_PWR_I2S1_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("IF1 DAC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5660_if1_dac_swap_mux),
+	SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("IF1 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5660_if1_adc_swap_mux),
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Output Side */
+	/* DAC mixer before sound effect  */
+	SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0, rt5660_dac_l_mix,
+		ARRAY_SIZE(rt5660_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0, rt5660_dac_r_mix,
+		ARRAY_SIZE(rt5660_dac_r_mix)),
+
+	/* DAC Mixer */
+	SND_SOC_DAPM_SUPPLY("dac stereo1 filter", RT5660_PWR_DIG2,
+		RT5660_PWR_DAC_S1F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5660_sto_dac_l_mix, ARRAY_SIZE(rt5660_sto_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5660_sto_dac_r_mix, ARRAY_SIZE(rt5660_sto_dac_r_mix)),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC L1", NULL, RT5660_PWR_DIG1,
+			RT5660_PWR_DAC_L1_BIT, 0),
+	SND_SOC_DAPM_DAC("DAC R1", NULL, RT5660_PWR_DIG1,
+			RT5660_PWR_DAC_R1_BIT, 0),
+
+	/* OUT Mixer */
+	SND_SOC_DAPM_MIXER("SPK MIX", RT5660_PWR_MIXER, RT5660_PWR_SM_BIT,
+		0, rt5660_spk_mix, ARRAY_SIZE(rt5660_spk_mix)),
+	SND_SOC_DAPM_MIXER("OUT MIXL", RT5660_PWR_MIXER, RT5660_PWR_OM_L_BIT,
+		0, rt5660_out_l_mix, ARRAY_SIZE(rt5660_out_l_mix)),
+	SND_SOC_DAPM_MIXER("OUT MIXR", RT5660_PWR_MIXER, RT5660_PWR_OM_R_BIT,
+		0, rt5660_out_r_mix, ARRAY_SIZE(rt5660_out_r_mix)),
+
+	/* Output Volume */
+	SND_SOC_DAPM_SWITCH("SPKVOL", RT5660_PWR_VOL,
+		RT5660_PWR_SV_BIT, 0, &spk_vol_control),
+	SND_SOC_DAPM_PGA("DAC 1", SND_SOC_NOPM,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("LOUTVOL", SND_SOC_NOPM,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_SWITCH("LOUTVOL L", SND_SOC_NOPM,
+		RT5660_PWR_LV_L_BIT, 0, &lout_l_vol_control),
+	SND_SOC_DAPM_SWITCH("LOUTVOL R", SND_SOC_NOPM,
+		RT5660_PWR_LV_R_BIT, 0, &lout_r_vol_control),
+
+	/* HPO/LOUT/Mono Mixer */
+	SND_SOC_DAPM_MIXER("SPO MIX", SND_SOC_NOPM, 0,
+		0, rt5660_spo_mix, ARRAY_SIZE(rt5660_spo_mix)),
+	SND_SOC_DAPM_MIXER("LOUT MIX", SND_SOC_NOPM, 0, 0,
+		rt5660_lout_mix, ARRAY_SIZE(rt5660_lout_mix)),
+	SND_SOC_DAPM_SUPPLY("VREF HP", RT5660_GEN_CTRL1,
+		RT5660_PWR_VREF_HP_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA_S("LOUT amp", 1, RT5660_PWR_ANLG1,
+		RT5660_PWR_HA_BIT, 0, rt5660_lout_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_S("SPK amp", 1, RT5660_PWR_DIG1,
+		RT5660_PWR_CLS_D_BIT, 0, NULL, 0),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("LOUTL"),
+	SND_SOC_DAPM_OUTPUT("LOUTR"),
+	SND_SOC_DAPM_OUTPUT("SPO"),
+};
+
+static const struct snd_soc_dapm_route rt5660_dapm_routes[] = {
+	{ "MICBIAS1", NULL, "LDO2" },
+	{ "MICBIAS2", NULL, "LDO2" },
+
+	{ "BST1", NULL, "IN1P" },
+	{ "BST1", NULL, "IN1N" },
+	{ "BST2", NULL, "IN2P" },
+	{ "BST3", NULL, "IN3P" },
+	{ "BST3", NULL, "IN3N" },
+
+	{ "RECMIXL", "BST3 Switch", "BST3" },
+	{ "RECMIXL", "BST2 Switch", "BST2" },
+	{ "RECMIXL", "BST1 Switch", "BST1" },
+	{ "RECMIXL", "OUT MIXL Switch", "OUT MIXL" },
+
+	{ "RECMIXR", "BST3 Switch", "BST3" },
+	{ "RECMIXR", "BST2 Switch", "BST2" },
+	{ "RECMIXR", "BST1 Switch", "BST1" },
+	{ "RECMIXR", "OUT MIXR Switch", "OUT MIXR" },
+
+	{ "ADC L", NULL, "RECMIXL" },
+	{ "ADC L", NULL, "ADC L power" },
+	{ "ADC L", NULL, "ADC clock" },
+	{ "ADC R", NULL, "RECMIXR" },
+	{ "ADC R", NULL, "ADC R power" },
+	{ "ADC R", NULL, "ADC clock" },
+
+	{"DMIC L1", NULL, "DMIC CLK"},
+	{"DMIC L1", NULL, "DMIC Power"},
+	{"DMIC R1", NULL, "DMIC CLK"},
+	{"DMIC R1", NULL, "DMIC Power"},
+
+	{ "Sto1 ADC MIXL", "ADC1 Switch", "ADC L" },
+	{ "Sto1 ADC MIXL", "ADC2 Switch", "DMIC L1" },
+	{ "Sto1 ADC MIXR", "ADC1 Switch", "ADC R" },
+	{ "Sto1 ADC MIXR", "ADC2 Switch", "DMIC R1" },
+
+	{ "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" },
+	{ "Stereo1 ADC MIXL", NULL, "adc stereo1 filter" },
+	{ "adc stereo1 filter", NULL, "PLL1", rt5660_is_sys_clk_from_pll },
+
+	{ "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" },
+	{ "Stereo1 ADC MIXR", NULL, "adc stereo1 filter" },
+	{ "adc stereo1 filter", NULL, "PLL1", rt5660_is_sys_clk_from_pll },
+
+	{ "IF1 ADC", NULL, "Stereo1 ADC MIXL" },
+	{ "IF1 ADC", NULL, "Stereo1 ADC MIXR" },
+	{ "IF1 ADC", NULL, "I2S1" },
+
+	{ "IF1 ADC Swap Mux", "L/R", "IF1 ADC" },
+	{ "IF1 ADC Swap Mux", "R/L", "IF1 ADC" },
+	{ "IF1 ADC Swap Mux", "L/L", "IF1 ADC" },
+	{ "IF1 ADC Swap Mux", "R/R", "IF1 ADC" },
+	{ "AIF1TX", NULL, "IF1 ADC Swap Mux" },
+
+	{ "IF1 DAC", NULL, "AIF1RX" },
+	{ "IF1 DAC", NULL, "I2S1" },
+
+	{ "IF1 DAC Swap Mux", "L/R", "IF1 DAC" },
+	{ "IF1 DAC Swap Mux", "R/L", "IF1 DAC" },
+	{ "IF1 DAC Swap Mux", "L/L", "IF1 DAC" },
+	{ "IF1 DAC Swap Mux", "R/R", "IF1 DAC" },
+
+	{ "IF1 DAC L", NULL, "IF1 DAC Swap Mux" },
+	{ "IF1 DAC R", NULL, "IF1 DAC Swap Mux" },
+
+	{ "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL" },
+	{ "DAC1 MIXL", "DAC1 Switch", "IF1 DAC L" },
+	{ "DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR" },
+	{ "DAC1 MIXR", "DAC1 Switch", "IF1 DAC R" },
+
+	{ "Stereo DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" },
+	{ "Stereo DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" },
+	{ "Stereo DAC MIXL", NULL, "dac stereo1 filter" },
+	{ "dac stereo1 filter", NULL, "PLL1", rt5660_is_sys_clk_from_pll },
+	{ "Stereo DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" },
+	{ "Stereo DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" },
+	{ "Stereo DAC MIXR", NULL, "dac stereo1 filter" },
+	{ "dac stereo1 filter", NULL, "PLL1", rt5660_is_sys_clk_from_pll },
+
+	{ "DAC L1", NULL, "Stereo DAC MIXL" },
+	{ "DAC R1", NULL, "Stereo DAC MIXR" },
+
+	{ "SPK MIX", "BST3 Switch", "BST3" },
+	{ "SPK MIX", "BST1 Switch", "BST1" },
+	{ "SPK MIX", "DACL Switch", "DAC L1" },
+	{ "SPK MIX", "DACR Switch", "DAC R1" },
+	{ "SPK MIX", "OUTMIXL Switch", "OUT MIXL" },
+
+	{ "OUT MIXL", "BST3 Switch", "BST3" },
+	{ "OUT MIXL", "BST2 Switch", "BST2" },
+	{ "OUT MIXL", "BST1 Switch", "BST1" },
+	{ "OUT MIXL", "RECMIXL Switch", "RECMIXL" },
+	{ "OUT MIXL", "DACR Switch", "DAC R1" },
+	{ "OUT MIXL", "DACL Switch", "DAC L1" },
+
+	{ "OUT MIXR", "BST2 Switch", "BST2" },
+	{ "OUT MIXR", "BST1 Switch", "BST1" },
+	{ "OUT MIXR", "RECMIXR Switch", "RECMIXR" },
+	{ "OUT MIXR", "DACR Switch", "DAC R1" },
+	{ "OUT MIXR", "DACL Switch", "DAC L1" },
+
+	{ "SPO MIX", "DACR Switch", "DAC R1" },
+	{ "SPO MIX", "DACL Switch", "DAC L1" },
+	{ "SPO MIX", "SPKVOL Switch", "SPKVOL" },
+	{ "SPO MIX", "BST1 Switch", "BST1" },
+
+	{ "SPKVOL", "Switch", "SPK MIX" },
+	{ "LOUTVOL L", "Switch", "OUT MIXL" },
+	{ "LOUTVOL R", "Switch", "OUT MIXR" },
+
+	{ "LOUTVOL", NULL, "LOUTVOL L" },
+	{ "LOUTVOL", NULL, "LOUTVOL R" },
+
+	{ "DAC 1", NULL, "DAC L1" },
+	{ "DAC 1", NULL, "DAC R1" },
+
+	{ "LOUT MIX", "DAC Switch", "DAC 1" },
+	{ "LOUT MIX", "OUTMIX Switch", "LOUTVOL" },
+
+	{ "LOUT amp", NULL, "LOUT MIX" },
+	{ "LOUT amp", NULL, "VREF HP" },
+	{ "LOUTL", NULL, "LOUT amp" },
+	{ "LOUTR", NULL, "LOUT amp" },
+
+	{ "SPK amp", NULL, "SPO MIX" },
+	{ "SPO", NULL, "SPK amp" },
+};
+
+static int rt5660_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 rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+	unsigned int val_len = 0, val_clk, mask_clk;
+	int pre_div, bclk_ms, frame_size;
+
+	rt5660->lrck[dai->id] = params_rate(params);
+	pre_div = rl6231_get_clk_info(rt5660->sysclk, rt5660->lrck[dai->id]);
+	if (pre_div < 0) {
+		dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n",
+			rt5660->lrck[dai->id], dai->id);
+		return -EINVAL;
+	}
+
+	frame_size = snd_soc_params_to_frame_size(params);
+	if (frame_size < 0) {
+		dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+		return frame_size;
+	}
+
+	if (frame_size > 32)
+		bclk_ms = 1;
+	else
+		bclk_ms = 0;
+
+	rt5660->bclk[dai->id] = rt5660->lrck[dai->id] * (32 << bclk_ms);
+
+	dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n",
+		rt5660->bclk[dai->id], rt5660->lrck[dai->id]);
+	dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+				bclk_ms, pre_div, dai->id);
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		val_len |= RT5660_I2S_DL_20;
+		break;
+	case 24:
+		val_len |= RT5660_I2S_DL_24;
+		break;
+	case 8:
+		val_len |= RT5660_I2S_DL_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5660_AIF1:
+		mask_clk = RT5660_I2S_BCLK_MS1_MASK | RT5660_I2S_PD1_MASK;
+		val_clk = bclk_ms << RT5660_I2S_BCLK_MS1_SFT |
+			pre_div << RT5660_I2S_PD1_SFT;
+		snd_soc_update_bits(codec, RT5660_I2S1_SDP, RT5660_I2S_DL_MASK,
+			val_len);
+		snd_soc_update_bits(codec, RT5660_ADDA_CLK1, mask_clk, val_clk);
+		break;
+
+	default:
+		dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rt5660_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+	unsigned int reg_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		rt5660->master[dai->id] = 1;
+		break;
+
+	case SND_SOC_DAIFMT_CBS_CFS:
+		reg_val |= RT5660_I2S_MS_S;
+		rt5660->master[dai->id] = 0;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+
+	case SND_SOC_DAIFMT_IB_NF:
+		reg_val |= RT5660_I2S_BP_INV;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg_val |= RT5660_I2S_DF_LEFT;
+		break;
+
+	case SND_SOC_DAIFMT_DSP_A:
+		reg_val |= RT5660_I2S_DF_PCM_A;
+		break;
+
+	case SND_SOC_DAIFMT_DSP_B:
+		reg_val  |= RT5660_I2S_DF_PCM_B;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5660_AIF1:
+		snd_soc_update_bits(codec, RT5660_I2S1_SDP,
+			RT5660_I2S_MS_MASK | RT5660_I2S_BP_MASK |
+			RT5660_I2S_DF_MASK, reg_val);
+		break;
+
+	default:
+		dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rt5660_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+	unsigned int reg_val = 0;
+
+	if (freq == rt5660->sysclk && clk_id == rt5660->sysclk_src)
+		return 0;
+
+	switch (clk_id) {
+	case RT5660_SCLK_S_MCLK:
+		reg_val |= RT5660_SCLK_SRC_MCLK;
+		break;
+
+	case RT5660_SCLK_S_PLL1:
+		reg_val |= RT5660_SCLK_SRC_PLL1;
+		break;
+
+	case RT5660_SCLK_S_RCCLK:
+		reg_val |= RT5660_SCLK_SRC_RCCLK;
+		break;
+
+	default:
+		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, RT5660_GLB_CLK, RT5660_SCLK_SRC_MASK,
+		reg_val);
+
+	rt5660->sysclk = freq;
+	rt5660->sysclk_src = clk_id;
+
+	dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+
+	return 0;
+}
+
+static int rt5660_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+			unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+	struct rl6231_pll_code pll_code;
+	int ret;
+
+	if (source == rt5660->pll_src && freq_in == rt5660->pll_in &&
+		freq_out == rt5660->pll_out)
+		return 0;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(codec->dev, "PLL disabled\n");
+
+		rt5660->pll_in = 0;
+		rt5660->pll_out = 0;
+		snd_soc_update_bits(codec, RT5660_GLB_CLK,
+			RT5660_SCLK_SRC_MASK, RT5660_SCLK_SRC_MCLK);
+		return 0;
+	}
+
+	switch (source) {
+	case RT5660_PLL1_S_MCLK:
+		snd_soc_update_bits(codec, RT5660_GLB_CLK,
+			RT5660_PLL1_SRC_MASK, RT5660_PLL1_SRC_MCLK);
+		break;
+
+	case RT5660_PLL1_S_BCLK:
+		snd_soc_update_bits(codec, RT5660_GLB_CLK,
+			RT5660_PLL1_SRC_MASK, RT5660_PLL1_SRC_BCLK1);
+		break;
+
+	default:
+		dev_err(codec->dev, "Unknown PLL source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+	if (ret < 0) {
+		dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+		return ret;
+	}
+
+	dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n",
+		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+		pll_code.n_code, pll_code.k_code);
+
+	snd_soc_write(codec, RT5660_PLL_CTRL1,
+		pll_code.n_code << RT5660_PLL_N_SFT | pll_code.k_code);
+	snd_soc_write(codec, RT5660_PLL_CTRL2,
+		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5660_PLL_M_SFT |
+		pll_code.m_bp << RT5660_PLL_M_BP_SFT);
+
+	rt5660->pll_in = freq_in;
+	rt5660->pll_out = freq_out;
+	rt5660->pll_src = source;
+
+	return 0;
+}
+
+static int rt5660_set_bias_level(struct snd_soc_codec *codec,
+			enum snd_soc_bias_level level)
+{
+	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		snd_soc_update_bits(codec, RT5660_GEN_CTRL1,
+			RT5660_DIG_GATE_CTRL, RT5660_DIG_GATE_CTRL);
+
+		if (IS_ERR(rt5660->mclk))
+			break;
+
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) {
+			clk_disable_unprepare(rt5660->mclk);
+		} else {
+			ret = clk_prepare_enable(rt5660->mclk);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+			snd_soc_update_bits(codec, RT5660_PWR_ANLG1,
+				RT5660_PWR_VREF1 | RT5660_PWR_MB |
+				RT5660_PWR_BG | RT5660_PWR_VREF2,
+				RT5660_PWR_VREF1 | RT5660_PWR_MB |
+				RT5660_PWR_BG | RT5660_PWR_VREF2);
+			usleep_range(10000, 15000);
+			snd_soc_update_bits(codec, RT5660_PWR_ANLG1,
+				RT5660_PWR_FV1 | RT5660_PWR_FV2,
+				RT5660_PWR_FV1 | RT5660_PWR_FV2);
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_update_bits(codec, RT5660_GEN_CTRL1,
+			RT5660_DIG_GATE_CTRL, 0);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5660_probe(struct snd_soc_codec *codec)
+{
+	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+
+	rt5660->codec = codec;
+
+	return 0;
+}
+
+static int rt5660_remove(struct snd_soc_codec *codec)
+{
+	return snd_soc_write(codec, RT5660_RESET, 0);
+}
+
+#ifdef CONFIG_PM
+static int rt5660_suspend(struct snd_soc_codec *codec)
+{
+	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+
+	regcache_cache_only(rt5660->regmap, true);
+	regcache_mark_dirty(rt5660->regmap);
+
+	return 0;
+}
+
+static int rt5660_resume(struct snd_soc_codec *codec)
+{
+	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+
+	if (rt5660->pdata.poweroff_codec_in_suspend)
+		usleep_range(350000, 400000);
+
+	regcache_cache_only(rt5660->regmap, false);
+	regcache_sync(rt5660->regmap);
+
+	return 0;
+}
+#else
+#define rt5660_suspend NULL
+#define rt5660_resume NULL
+#endif
+
+#define RT5660_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT5660_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5660_aif_dai_ops = {
+	.hw_params = rt5660_hw_params,
+	.set_fmt = rt5660_set_dai_fmt,
+	.set_sysclk = rt5660_set_dai_sysclk,
+	.set_pll = rt5660_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver rt5660_dai[] = {
+	{
+		.name = "rt5660-aif1",
+		.id = RT5660_AIF1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5660_STEREO_RATES,
+			.formats = RT5660_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5660_STEREO_RATES,
+			.formats = RT5660_FORMATS,
+		},
+		.ops = &rt5660_aif_dai_ops,
+	},
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_rt5660 = {
+	.probe = rt5660_probe,
+	.remove = rt5660_remove,
+	.suspend = rt5660_suspend,
+	.resume = rt5660_resume,
+	.set_bias_level = rt5660_set_bias_level,
+	.idle_bias_off = true,
+	.component_driver = {
+		.controls		= rt5660_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt5660_snd_controls),
+		.dapm_widgets		= rt5660_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt5660_dapm_widgets),
+		.dapm_routes		= rt5660_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt5660_dapm_routes),
+	},
+};
+
+static const struct regmap_config rt5660_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+	.use_single_rw = true,
+
+	.max_register = RT5660_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5660_ranges) *
+					       RT5660_PR_SPACING),
+	.volatile_reg = rt5660_volatile_register,
+	.readable_reg = rt5660_readable_register,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5660_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5660_reg),
+	.ranges = rt5660_ranges,
+	.num_ranges = ARRAY_SIZE(rt5660_ranges),
+};
+
+static const struct i2c_device_id rt5660_i2c_id[] = {
+	{ "rt5660", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, rt5660_i2c_id);
+
+static const struct of_device_id rt5660_of_match[] = {
+	{ .compatible = "realtek,rt5660", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rt5660_of_match);
+
+static const struct acpi_device_id rt5660_acpi_match[] = {
+	{ "10EC5660", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, rt5660_acpi_match);
+
+static int rt5660_parse_dt(struct rt5660_priv *rt5660, struct device *dev)
+{
+	rt5660->pdata.in1_diff = device_property_read_bool(dev,
+					"realtek,in1-differential");
+	rt5660->pdata.in3_diff = device_property_read_bool(dev,
+					"realtek,in3-differential");
+	rt5660->pdata.poweroff_codec_in_suspend = device_property_read_bool(dev,
+					"realtek,poweroff-in-suspend");
+	device_property_read_u32(dev, "realtek,dmic1-data-pin",
+		&rt5660->pdata.dmic1_data_pin);
+
+	return 0;
+}
+
+static int rt5660_i2c_probe(struct i2c_client *i2c,
+		    const struct i2c_device_id *id)
+{
+	struct rt5660_platform_data *pdata = dev_get_platdata(&i2c->dev);
+	struct rt5660_priv *rt5660;
+	int ret;
+	unsigned int val;
+
+	rt5660 = devm_kzalloc(&i2c->dev, sizeof(struct rt5660_priv),
+		GFP_KERNEL);
+
+	if (rt5660 == NULL)
+		return -ENOMEM;
+
+	/* Check if MCLK provided */
+	rt5660->mclk = devm_clk_get(&i2c->dev, "mclk");
+	if (PTR_ERR(rt5660->mclk) == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+
+	i2c_set_clientdata(i2c, rt5660);
+
+	if (pdata)
+		rt5660->pdata = *pdata;
+	else if (i2c->dev.of_node)
+		rt5660_parse_dt(rt5660, &i2c->dev);
+
+	rt5660->regmap = devm_regmap_init_i2c(i2c, &rt5660_regmap);
+	if (IS_ERR(rt5660->regmap)) {
+		ret = PTR_ERR(rt5660->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	regmap_read(rt5660->regmap, RT5660_VENDOR_ID2, &val);
+	if (val != RT5660_DEVICE_ID) {
+		dev_err(&i2c->dev,
+			"Device with ID register %#x is not rt5660\n", val);
+		return -ENODEV;
+	}
+
+	regmap_write(rt5660->regmap, RT5660_RESET, 0);
+
+	ret = regmap_register_patch(rt5660->regmap, rt5660_patch,
+				    ARRAY_SIZE(rt5660_patch));
+	if (ret != 0)
+		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+	if (rt5660->pdata.dmic1_data_pin) {
+		regmap_update_bits(rt5660->regmap, RT5660_GPIO_CTRL1,
+			RT5660_GP1_PIN_MASK, RT5660_GP1_PIN_DMIC1_SCL);
+
+		if (rt5660->pdata.dmic1_data_pin == RT5660_DMIC1_DATA_GPIO2)
+			regmap_update_bits(rt5660->regmap, RT5660_DMIC_CTRL1,
+				RT5660_SEL_DMIC_DATA_MASK,
+				RT5660_SEL_DMIC_DATA_GPIO2);
+		else if (rt5660->pdata.dmic1_data_pin == RT5660_DMIC1_DATA_IN1P)
+			regmap_update_bits(rt5660->regmap, RT5660_DMIC_CTRL1,
+				RT5660_SEL_DMIC_DATA_MASK,
+				RT5660_SEL_DMIC_DATA_IN1P);
+	}
+
+	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5660,
+				      rt5660_dai, ARRAY_SIZE(rt5660_dai));
+}
+
+static int rt5660_i2c_remove(struct i2c_client *i2c)
+{
+	snd_soc_unregister_codec(&i2c->dev);
+
+	return 0;
+}
+
+static struct i2c_driver rt5660_i2c_driver = {
+	.driver = {
+		.name = "rt5660",
+		.acpi_match_table = ACPI_PTR(rt5660_acpi_match),
+		.of_match_table = of_match_ptr(rt5660_of_match),
+	},
+	.probe = rt5660_i2c_probe,
+	.remove   = rt5660_i2c_remove,
+	.id_table = rt5660_i2c_id,
+};
+module_i2c_driver(rt5660_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5660 driver");
+MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5660.h b/sound/soc/codecs/rt5660.h
new file mode 100644
index 0000000..6cdb926
--- /dev/null
+++ b/sound/soc/codecs/rt5660.h
@@ -0,0 +1,847 @@
+/*
+ * rt5660.h  --  RT5660 ALSA SoC audio driver
+ *
+ * Copyright 2016 Realtek Semiconductor Corp.
+ * Author: Oder Chiou <oder_chiou@realtek.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 _RT5660_H
+#define _RT5660_H
+
+#include <linux/clk.h>
+#include <sound/rt5660.h>
+
+/* Info */
+#define RT5660_RESET				0x00
+#define RT5660_VENDOR_ID			0xfd
+#define RT5660_VENDOR_ID1			0xfe
+#define RT5660_VENDOR_ID2			0xff
+/*  I/O - Output */
+#define RT5660_SPK_VOL				0x01
+#define RT5660_LOUT_VOL				0x02
+/* I/O - Input */
+#define RT5660_IN1_IN2				0x0d
+#define RT5660_IN3_IN4				0x0e
+/* I/O - ADC/DAC/DMIC */
+#define RT5660_DAC1_DIG_VOL			0x19
+#define RT5660_STO1_ADC_DIG_VOL			0x1c
+#define RT5660_ADC_BST_VOL1			0x1e
+/* Mixer - D-D */
+#define RT5660_STO1_ADC_MIXER			0x27
+#define RT5660_AD_DA_MIXER			0x29
+#define RT5660_STO_DAC_MIXER			0x2a
+#define RT5660_DIG_INF1_DATA			0x2f
+/* Mixer - ADC */
+#define RT5660_REC_L1_MIXER			0x3b
+#define RT5660_REC_L2_MIXER			0x3c
+#define RT5660_REC_R1_MIXER			0x3d
+#define RT5660_REC_R2_MIXER			0x3e
+/* Mixer - DAC */
+#define RT5660_LOUT_MIXER			0x45
+#define RT5660_SPK_MIXER			0x46
+#define RT5660_SPO_MIXER			0x48
+#define RT5660_SPO_CLSD_RATIO			0x4a
+#define RT5660_OUT_L_GAIN1			0x4d
+#define RT5660_OUT_L_GAIN2			0x4e
+#define RT5660_OUT_L1_MIXER			0x4f
+#define RT5660_OUT_R_GAIN1			0x50
+#define RT5660_OUT_R_GAIN2			0x51
+#define RT5660_OUT_R1_MIXER			0x52
+/* Power */
+#define RT5660_PWR_DIG1				0x61
+#define RT5660_PWR_DIG2				0x62
+#define RT5660_PWR_ANLG1			0x63
+#define RT5660_PWR_ANLG2			0x64
+#define RT5660_PWR_MIXER			0x65
+#define RT5660_PWR_VOL				0x66
+/* Private Register Control */
+#define RT5660_PRIV_INDEX			0x6a
+#define RT5660_PRIV_DATA			0x6c
+/* Format - ADC/DAC */
+#define RT5660_I2S1_SDP				0x70
+#define RT5660_ADDA_CLK1			0x73
+#define RT5660_ADDA_CLK2			0x74
+#define RT5660_DMIC_CTRL1			0x75
+/* Function - Analog */
+#define RT5660_GLB_CLK				0x80
+#define RT5660_PLL_CTRL1			0x81
+#define RT5660_PLL_CTRL2			0x82
+#define RT5660_CLSD_AMP_OC_CTRL			0x8c
+#define RT5660_CLSD_AMP_CTRL			0x8d
+#define RT5660_LOUT_AMP_CTRL			0x8e
+#define RT5660_SPK_AMP_SPKVDD			0x92
+#define RT5660_MICBIAS				0x93
+#define RT5660_CLSD_OUT_CTRL1			0xa1
+#define RT5660_CLSD_OUT_CTRL2			0xa2
+#define RT5660_DIPOLE_MIC_CTRL1			0xa3
+#define RT5660_DIPOLE_MIC_CTRL2			0xa4
+#define RT5660_DIPOLE_MIC_CTRL3			0xa5
+#define RT5660_DIPOLE_MIC_CTRL4			0xa6
+#define RT5660_DIPOLE_MIC_CTRL5			0xa7
+#define RT5660_DIPOLE_MIC_CTRL6			0xa8
+#define RT5660_DIPOLE_MIC_CTRL7			0xa9
+#define RT5660_DIPOLE_MIC_CTRL8			0xaa
+#define RT5660_DIPOLE_MIC_CTRL9			0xab
+#define RT5660_DIPOLE_MIC_CTRL10		0xac
+#define RT5660_DIPOLE_MIC_CTRL11		0xad
+#define RT5660_DIPOLE_MIC_CTRL12		0xae
+/* Function - Digital */
+#define RT5660_EQ_CTRL1				0xb0
+#define RT5660_EQ_CTRL2				0xb1
+#define RT5660_DRC_AGC_CTRL1			0xb3
+#define RT5660_DRC_AGC_CTRL2			0xb4
+#define RT5660_DRC_AGC_CTRL3			0xb5
+#define RT5660_DRC_AGC_CTRL4			0xb6
+#define RT5660_DRC_AGC_CTRL5			0xb7
+#define RT5660_JD_CTRL				0xbb
+#define RT5660_IRQ_CTRL1			0xbd
+#define RT5660_IRQ_CTRL2			0xbe
+#define RT5660_INT_IRQ_ST			0xbf
+#define RT5660_GPIO_CTRL1			0xc0
+#define RT5660_GPIO_CTRL2			0xc2
+#define RT5660_WIND_FILTER_CTRL1		0xd3
+#define RT5660_SV_ZCD1				0xd9
+#define RT5660_SV_ZCD2				0xda
+#define RT5660_DRC1_LM_CTRL1			0xe0
+#define RT5660_DRC1_LM_CTRL2			0xe1
+#define RT5660_DRC2_LM_CTRL1			0xe2
+#define RT5660_DRC2_LM_CTRL2			0xe3
+#define RT5660_MULTI_DRC_CTRL			0xe4
+#define RT5660_DRC2_CTRL1			0xe5
+#define RT5660_DRC2_CTRL2			0xe6
+#define RT5660_DRC2_CTRL3			0xe7
+#define RT5660_DRC2_CTRL4			0xe8
+#define RT5660_DRC2_CTRL5			0xe9
+#define RT5660_ALC_PGA_CTRL1			0xea
+#define RT5660_ALC_PGA_CTRL2			0xeb
+#define RT5660_ALC_PGA_CTRL3			0xec
+#define RT5660_ALC_PGA_CTRL4			0xed
+#define RT5660_ALC_PGA_CTRL5			0xee
+#define RT5660_ALC_PGA_CTRL6			0xef
+#define RT5660_ALC_PGA_CTRL7			0xf0
+
+/* General Control */
+#define RT5660_GEN_CTRL1			0xfa
+#define RT5660_GEN_CTRL2			0xfb
+#define RT5660_GEN_CTRL3			0xfc
+
+/* Index of Codec Private Register definition */
+#define RT5660_CHOP_DAC_ADC			0x3d
+
+/* Global Definition */
+#define RT5660_L_MUTE				(0x1 << 15)
+#define RT5660_L_MUTE_SFT			15
+#define RT5660_VOL_L_MUTE			(0x1 << 14)
+#define RT5660_VOL_L_SFT			14
+#define RT5660_R_MUTE				(0x1 << 7)
+#define RT5660_R_MUTE_SFT			7
+#define RT5660_VOL_R_MUTE			(0x1 << 6)
+#define RT5660_VOL_R_SFT			6
+#define RT5660_L_VOL_MASK			(0x3f << 8)
+#define RT5660_L_VOL_SFT			8
+#define RT5660_R_VOL_MASK			(0x3f)
+#define RT5660_R_VOL_SFT			0
+
+/* IN1 and IN2 Control (0x0d) */
+#define RT5660_IN_DF1				(0x1 << 15)
+#define RT5660_IN_SFT1				15
+#define RT5660_BST_MASK1			(0x7f << 8)
+#define RT5660_BST_SFT1				8
+#define RT5660_IN_DF2				(0x1 << 7)
+#define RT5660_IN_SFT2				7
+#define RT5660_BST_MASK2			(0x7f << 0)
+#define RT5660_BST_SFT2				0
+
+/* IN3 and IN4 Control (0x0e) */
+#define RT5660_IN_DF3				(0x1 << 15)
+#define RT5660_IN_SFT3				15
+#define RT5660_BST_MASK3			(0x7f << 8)
+#define RT5660_BST_SFT3				8
+#define RT5660_IN_DF4				(0x1 << 7)
+#define RT5660_IN_SFT4				7
+#define RT5660_BST_MASK4			(0x7f << 0)
+#define RT5660_BST_SFT4				0
+
+/* DAC1 Digital Volume (0x19) */
+#define RT5660_DAC_L1_VOL_MASK			(0x7f << 9)
+#define RT5660_DAC_L1_VOL_SFT			9
+#define RT5660_DAC_R1_VOL_MASK			(0x7f << 1)
+#define RT5660_DAC_R1_VOL_SFT			1
+
+/* ADC Digital Volume Control (0x1c) */
+#define RT5660_ADC_L_VOL_MASK			(0x3f << 9)
+#define RT5660_ADC_L_VOL_SFT			9
+#define RT5660_ADC_R_VOL_MASK			(0x3f << 1)
+#define RT5660_ADC_R_VOL_SFT			1
+
+/* ADC Boost Volume Control (0x1e) */
+#define RT5660_STO1_ADC_L_BST_MASK		(0x3 << 14)
+#define RT5660_STO1_ADC_L_BST_SFT		14
+#define RT5660_STO1_ADC_R_BST_MASK		(0x3 << 12)
+#define RT5660_STO1_ADC_R_BST_SFT		12
+
+/* Stereo ADC Mixer Control (0x27) */
+#define RT5660_M_ADC_L1				(0x1 << 14)
+#define RT5660_M_ADC_L1_SFT			14
+#define RT5660_M_ADC_L2				(0x1 << 13)
+#define RT5660_M_ADC_L2_SFT			13
+#define RT5660_M_ADC_R1				(0x1 << 6)
+#define RT5660_M_ADC_R1_SFT			6
+#define RT5660_M_ADC_R2				(0x1 << 5)
+#define RT5660_M_ADC_R2_SFT			5
+
+/* ADC Mixer to DAC Mixer Control (0x29) */
+#define RT5660_M_ADCMIX_L			(0x1 << 15)
+#define RT5660_M_ADCMIX_L_SFT			15
+#define RT5660_M_DAC1_L				(0x1 << 14)
+#define RT5660_M_DAC1_L_SFT			14
+#define RT5660_M_ADCMIX_R			(0x1 << 7)
+#define RT5660_M_ADCMIX_R_SFT			7
+#define RT5660_M_DAC1_R				(0x1 << 6)
+#define RT5660_M_DAC1_R_SFT			6
+
+/* Stereo DAC Mixer Control (0x2a) */
+#define RT5660_M_DAC_L1				(0x1 << 14)
+#define RT5660_M_DAC_L1_SFT			14
+#define RT5660_DAC_L1_STO_L_VOL_MASK		(0x1 << 13)
+#define RT5660_DAC_L1_STO_L_VOL_SFT		13
+#define RT5660_M_DAC_R1_STO_L			(0x1 << 9)
+#define RT5660_M_DAC_R1_STO_L_SFT		9
+#define RT5660_DAC_R1_STO_L_VOL_MASK		(0x1 << 8)
+#define RT5660_DAC_R1_STO_L_VOL_SFT		8
+#define RT5660_M_DAC_R1				(0x1 << 6)
+#define RT5660_M_DAC_R1_SFT			6
+#define RT5660_DAC_R1_STO_R_VOL_MASK		(0x1 << 5)
+#define RT5660_DAC_R1_STO_R_VOL_SFT		5
+#define RT5660_M_DAC_L1_STO_R			(0x1 << 1)
+#define RT5660_M_DAC_L1_STO_R_SFT		1
+#define RT5660_DAC_L1_STO_R_VOL_MASK		(0x1)
+#define RT5660_DAC_L1_STO_R_VOL_SFT		0
+
+/* Digital Interface Data Control (0x2f) */
+#define RT5660_IF1_DAC_IN_SEL			(0x3 << 14)
+#define RT5660_IF1_DAC_IN_SFT			14
+#define RT5660_IF1_ADC_IN_SEL			(0x3 << 12)
+#define RT5660_IF1_ADC_IN_SFT			12
+
+/* REC Left Mixer Control 1 (0x3b) */
+#define RT5660_G_BST3_RM_L_MASK			(0x7 << 4)
+#define RT5660_G_BST3_RM_L_SFT			4
+#define RT5660_G_BST2_RM_L_MASK			(0x7 << 1)
+#define RT5660_G_BST2_RM_L_SFT			1
+
+/* REC Left Mixer Control 2 (0x3c) */
+#define RT5660_G_BST1_RM_L_MASK			(0x7 << 13)
+#define RT5660_G_BST1_RM_L_SFT			13
+#define RT5660_G_OM_L_RM_L_MASK			(0x7 << 10)
+#define RT5660_G_OM_L_RM_L_SFT			10
+#define RT5660_M_BST3_RM_L			(0x1 << 3)
+#define RT5660_M_BST3_RM_L_SFT			3
+#define RT5660_M_BST2_RM_L			(0x1 << 2)
+#define RT5660_M_BST2_RM_L_SFT			2
+#define RT5660_M_BST1_RM_L			(0x1 << 1)
+#define RT5660_M_BST1_RM_L_SFT			1
+#define RT5660_M_OM_L_RM_L			(0x1)
+#define RT5660_M_OM_L_RM_L_SFT			0
+
+/* REC Right Mixer Control 1 (0x3d) */
+#define RT5660_G_BST3_RM_R_MASK			(0x7 << 4)
+#define RT5660_G_BST3_RM_R_SFT			4
+#define RT5660_G_BST2_RM_R_MASK			(0x7 << 1)
+#define RT5660_G_BST2_RM_R_SFT			1
+
+/* REC Right Mixer Control 2 (0x3e) */
+#define RT5660_G_BST1_RM_R_MASK			(0x7 << 13)
+#define RT5660_G_BST1_RM_R_SFT			13
+#define RT5660_G_OM_R_RM_R_MASK			(0x7 << 10)
+#define RT5660_G_OM_R_RM_R_SFT			10
+#define RT5660_M_BST3_RM_R			(0x1 << 3)
+#define RT5660_M_BST3_RM_R_SFT			3
+#define RT5660_M_BST2_RM_R			(0x1 << 2)
+#define RT5660_M_BST2_RM_R_SFT			2
+#define RT5660_M_BST1_RM_R			(0x1 << 1)
+#define RT5660_M_BST1_RM_R_SFT			1
+#define RT5660_M_OM_R_RM_R			(0x1)
+#define RT5660_M_OM_R_RM_R_SFT			0
+
+/* LOUTMIX Control (0x45) */
+#define RT5660_M_DAC1_LM			(0x1 << 14)
+#define RT5660_M_DAC1_LM_SFT			14
+#define RT5660_M_LOVOL_M			(0x1 << 13)
+#define RT5660_M_LOVOL_LM_SFT			13
+
+/* SPK Mixer Control (0x46) */
+#define RT5660_G_BST3_SM_MASK			(0x3 << 14)
+#define RT5660_G_BST3_SM_SFT			14
+#define RT5660_G_BST1_SM_MASK			(0x3 << 12)
+#define RT5660_G_BST1_SM_SFT			12
+#define RT5660_G_DACl_SM_MASK			(0x3 << 10)
+#define RT5660_G_DACl_SM_SFT			10
+#define RT5660_G_DACR_SM_MASK			(0x3 << 8)
+#define RT5660_G_DACR_SM_SFT			8
+#define RT5660_G_OM_L_SM_MASK			(0x3 << 6)
+#define RT5660_G_OM_L_SM_SFT			6
+#define RT5660_M_DACR_SM			(0x1 << 5)
+#define RT5660_M_DACR_SM_SFT			5
+#define RT5660_M_BST1_SM			(0x1 << 4)
+#define RT5660_M_BST1_SM_SFT			4
+#define RT5660_M_BST3_SM			(0x1 << 3)
+#define RT5660_M_BST3_SM_SFT			3
+#define RT5660_M_DACL_SM			(0x1 << 2)
+#define RT5660_M_DACL_SM_SFT			2
+#define RT5660_M_OM_L_SM			(0x1 << 1)
+#define RT5660_M_OM_L_SM_SFT			1
+
+/* SPOMIX Control (0x48) */
+#define RT5660_M_DAC_R_SPM			(0x1 << 14)
+#define RT5660_M_DAC_R_SPM_SFT			14
+#define RT5660_M_DAC_L_SPM			(0x1 << 13)
+#define RT5660_M_DAC_L_SPM_SFT			13
+#define RT5660_M_SV_SPM				(0x1 << 12)
+#define RT5660_M_SV_SPM_SFT			12
+#define RT5660_M_BST1_SPM			(0x1 << 11)
+#define RT5660_M_BST1_SPM_SFT			11
+
+/* Output Left Mixer Control 1 (0x4d) */
+#define RT5660_G_BST3_OM_L_MASK			(0x7 << 13)
+#define RT5660_G_BST3_OM_L_SFT			13
+#define RT5660_G_BST2_OM_L_MASK			(0x7 << 10)
+#define RT5660_G_BST2_OM_L_SFT			10
+#define RT5660_G_BST1_OM_L_MASK			(0x7 << 7)
+#define RT5660_G_BST1_OM_L_SFT			7
+#define RT5660_G_RM_L_OM_L_MASK			(0x7 << 1)
+#define RT5660_G_RM_L_OM_L_SFT			1
+
+/* Output Left Mixer Control 2 (0x4e) */
+#define RT5660_G_DAC_R1_OM_L_MASK		(0x7 << 10)
+#define RT5660_G_DAC_R1_OM_L_SFT		10
+#define RT5660_G_DAC_L1_OM_L_MASK		(0x7 << 7)
+#define RT5660_G_DAC_L1_OM_L_SFT		7
+
+/* Output Left Mixer Control 3 (0x4f) */
+#define RT5660_M_BST3_OM_L			(0x1 << 5)
+#define RT5660_M_BST3_OM_L_SFT			5
+#define RT5660_M_BST2_OM_L			(0x1 << 4)
+#define RT5660_M_BST2_OM_L_SFT			4
+#define RT5660_M_BST1_OM_L			(0x1 << 3)
+#define RT5660_M_BST1_OM_L_SFT			3
+#define RT5660_M_RM_L_OM_L			(0x1 << 2)
+#define RT5660_M_RM_L_OM_L_SFT			2
+#define RT5660_M_DAC_R_OM_L			(0x1 << 1)
+#define RT5660_M_DAC_R_OM_L_SFT			1
+#define RT5660_M_DAC_L_OM_L			(0x1)
+#define RT5660_M_DAC_L_OM_L_SFT			0
+
+/* Output Right Mixer Control 1 (0x50) */
+#define RT5660_G_BST2_OM_R_MASK			(0x7 << 10)
+#define RT5660_G_BST2_OM_R_SFT			10
+#define RT5660_G_BST1_OM_R_MASK			(0x7 << 7)
+#define RT5660_G_BST1_OM_R_SFT			7
+#define RT5660_G_RM_R_OM_R_MASK			(0x7 << 1)
+#define RT5660_G_RM_R_OM_R_SFT			1
+
+/* Output Right Mixer Control 2 (0x51) */
+#define RT5660_G_DAC_L_OM_R_MASK		(0x7 << 10)
+#define RT5660_G_DAC_L_OM_R_SFT			10
+#define RT5660_G_DAC_R_OM_R_MASK		(0x7 << 7)
+#define RT5660_G_DAC_R_OM_R_SFT			7
+
+/* Output Right Mixer Control 3 (0x52) */
+#define RT5660_M_BST2_OM_R			(0x1 << 4)
+#define RT5660_M_BST2_OM_R_SFT			4
+#define RT5660_M_BST1_OM_R			(0x1 << 3)
+#define RT5660_M_BST1_OM_R_SFT			3
+#define RT5660_M_RM_R_OM_R			(0x1 << 2)
+#define RT5660_M_RM_R_OM_R_SFT			2
+#define RT5660_M_DAC_L_OM_R			(0x1 << 1)
+#define RT5660_M_DAC_L_OM_R_SFT			1
+#define RT5660_M_DAC_R_OM_R			(0x1)
+#define RT5660_M_DAC_R_OM_R_SFT			0
+
+/* Power Management for Digital 1 (0x61) */
+#define RT5660_PWR_I2S1				(0x1 << 15)
+#define RT5660_PWR_I2S1_BIT			15
+#define RT5660_PWR_DAC_L1			(0x1 << 12)
+#define RT5660_PWR_DAC_L1_BIT			12
+#define RT5660_PWR_DAC_R1			(0x1 << 11)
+#define RT5660_PWR_DAC_R1_BIT			11
+#define RT5660_PWR_ADC_L			(0x1 << 2)
+#define RT5660_PWR_ADC_L_BIT			2
+#define RT5660_PWR_ADC_R			(0x1 << 1)
+#define RT5660_PWR_ADC_R_BIT			1
+#define RT5660_PWR_CLS_D			(0x1)
+#define RT5660_PWR_CLS_D_BIT			0
+
+/* Power Management for Digital 2 (0x62) */
+#define RT5660_PWR_ADC_S1F			(0x1 << 15)
+#define RT5660_PWR_ADC_S1F_BIT			15
+#define RT5660_PWR_DAC_S1F			(0x1 << 11)
+#define RT5660_PWR_DAC_S1F_BIT			11
+
+/* Power Management for Analog 1 (0x63) */
+#define RT5660_PWR_VREF1			(0x1 << 15)
+#define RT5660_PWR_VREF1_BIT			15
+#define RT5660_PWR_FV1				(0x1 << 14)
+#define RT5660_PWR_FV1_BIT			14
+#define RT5660_PWR_MB				(0x1 << 13)
+#define RT5660_PWR_MB_BIT			13
+#define RT5660_PWR_BG				(0x1 << 11)
+#define RT5660_PWR_BG_BIT			11
+#define RT5660_PWR_HP_L				(0x1 << 7)
+#define RT5660_PWR_HP_L_BIT			7
+#define RT5660_PWR_HP_R				(0x1 << 6)
+#define RT5660_PWR_HP_R_BIT			6
+#define RT5660_PWR_HA				(0x1 << 5)
+#define RT5660_PWR_HA_BIT			5
+#define RT5660_PWR_VREF2			(0x1 << 4)
+#define RT5660_PWR_VREF2_BIT			4
+#define RT5660_PWR_FV2				(0x1 << 3)
+#define RT5660_PWR_FV2_BIT			3
+#define RT5660_PWR_LDO2				(0x1 << 2)
+#define RT5660_PWR_LDO2_BIT			2
+
+/* Power Management for Analog 2 (0x64) */
+#define RT5660_PWR_BST1				(0x1 << 15)
+#define RT5660_PWR_BST1_BIT			15
+#define RT5660_PWR_BST2				(0x1 << 14)
+#define RT5660_PWR_BST2_BIT			14
+#define RT5660_PWR_BST3				(0x1 << 13)
+#define RT5660_PWR_BST3_BIT			13
+#define RT5660_PWR_MB1				(0x1 << 11)
+#define RT5660_PWR_MB1_BIT			11
+#define RT5660_PWR_MB2				(0x1 << 10)
+#define RT5660_PWR_MB2_BIT			10
+#define RT5660_PWR_PLL				(0x1 << 9)
+#define RT5660_PWR_PLL_BIT			9
+
+/* Power Management for Mixer (0x65) */
+#define RT5660_PWR_OM_L				(0x1 << 15)
+#define RT5660_PWR_OM_L_BIT			15
+#define RT5660_PWR_OM_R				(0x1 << 14)
+#define RT5660_PWR_OM_R_BIT			14
+#define RT5660_PWR_SM				(0x1 << 13)
+#define RT5660_PWR_SM_BIT			13
+#define RT5660_PWR_RM_L				(0x1 << 11)
+#define RT5660_PWR_RM_L_BIT			11
+#define RT5660_PWR_RM_R				(0x1 << 10)
+#define RT5660_PWR_RM_R_BIT			10
+
+/* Power Management for Volume (0x66) */
+#define RT5660_PWR_SV				(0x1 << 15)
+#define RT5660_PWR_SV_BIT			15
+#define RT5660_PWR_LV_L				(0x1 << 11)
+#define RT5660_PWR_LV_L_BIT			11
+#define RT5660_PWR_LV_R				(0x1 << 10)
+#define RT5660_PWR_LV_R_BIT			10
+
+/* I2S1 Audio Serial Data Port Control (0x70) */
+#define RT5660_I2S_MS_MASK			(0x1 << 15)
+#define RT5660_I2S_MS_SFT			15
+#define RT5660_I2S_MS_M				(0x0 << 15)
+#define RT5660_I2S_MS_S				(0x1 << 15)
+#define RT5660_I2S_O_CP_MASK			(0x3 << 10)
+#define RT5660_I2S_O_CP_SFT			10
+#define RT5660_I2S_O_CP_OFF			(0x0 << 10)
+#define RT5660_I2S_O_CP_U_LAW			(0x1 << 10)
+#define RT5660_I2S_O_CP_A_LAW			(0x2 << 10)
+#define RT5660_I2S_I_CP_MASK			(0x3 << 8)
+#define RT5660_I2S_I_CP_SFT			8
+#define RT5660_I2S_I_CP_OFF			(0x0 << 8)
+#define RT5660_I2S_I_CP_U_LAW			(0x1 << 8)
+#define RT5660_I2S_I_CP_A_LAW			(0x2 << 8)
+#define RT5660_I2S_BP_MASK			(0x1 << 7)
+#define RT5660_I2S_BP_SFT			7
+#define RT5660_I2S_BP_NOR			(0x0 << 7)
+#define RT5660_I2S_BP_INV			(0x1 << 7)
+#define RT5660_I2S_DL_MASK			(0x3 << 2)
+#define RT5660_I2S_DL_SFT			2
+#define RT5660_I2S_DL_16			(0x0 << 2)
+#define RT5660_I2S_DL_20			(0x1 << 2)
+#define RT5660_I2S_DL_24			(0x2 << 2)
+#define RT5660_I2S_DL_8				(0x3 << 2)
+#define RT5660_I2S_DF_MASK			(0x3)
+#define RT5660_I2S_DF_SFT			0
+#define RT5660_I2S_DF_I2S			(0x0)
+#define RT5660_I2S_DF_LEFT			(0x1)
+#define RT5660_I2S_DF_PCM_A			(0x2)
+#define RT5660_I2S_DF_PCM_B			(0x3)
+
+/* ADC/DAC Clock Control 1 (0x73) */
+#define RT5660_I2S_BCLK_MS1_MASK		(0x1 << 15)
+#define RT5660_I2S_BCLK_MS1_SFT			15
+#define RT5660_I2S_BCLK_MS1_32			(0x0 << 15)
+#define RT5660_I2S_BCLK_MS1_64			(0x1 << 15)
+#define RT5660_I2S_PD1_MASK			(0x7 << 12)
+#define RT5660_I2S_PD1_SFT			12
+#define RT5660_I2S_PD1_1			(0x0 << 12)
+#define RT5660_I2S_PD1_2			(0x1 << 12)
+#define RT5660_I2S_PD1_3			(0x2 << 12)
+#define RT5660_I2S_PD1_4			(0x3 << 12)
+#define RT5660_I2S_PD1_6			(0x4 << 12)
+#define RT5660_I2S_PD1_8			(0x5 << 12)
+#define RT5660_I2S_PD1_12			(0x6 << 12)
+#define RT5660_I2S_PD1_16			(0x7 << 12)
+#define RT5660_DAC_OSR_MASK			(0x3 << 2)
+#define RT5660_DAC_OSR_SFT			2
+#define RT5660_DAC_OSR_128			(0x0 << 2)
+#define RT5660_DAC_OSR_64			(0x1 << 2)
+#define RT5660_DAC_OSR_32			(0x2 << 2)
+#define RT5660_DAC_OSR_16			(0x3 << 2)
+#define RT5660_ADC_OSR_MASK			(0x3)
+#define RT5660_ADC_OSR_SFT			0
+#define RT5660_ADC_OSR_128			(0x0)
+#define RT5660_ADC_OSR_64			(0x1)
+#define RT5660_ADC_OSR_32			(0x2)
+#define RT5660_ADC_OSR_16			(0x3)
+
+/* ADC/DAC Clock Control 2 (0x74) */
+#define RT5660_RESET_ADF			(0x1 << 13)
+#define RT5660_RESET_ADF_SFT			13
+#define RT5660_RESET_DAF			(0x1 << 12)
+#define RT5660_RESET_DAF_SFT			12
+#define RT5660_DAHPF_EN				(0x1 << 11)
+#define RT5660_DAHPF_EN_SFT			11
+#define RT5660_ADHPF_EN				(0x1 << 10)
+#define RT5660_ADHPF_EN_SFT			10
+
+/* Digital Microphone Control (0x75) */
+#define RT5660_DMIC_1_EN_MASK			(0x1 << 15)
+#define RT5660_DMIC_1_EN_SFT			15
+#define RT5660_DMIC_1_DIS			(0x0 << 15)
+#define RT5660_DMIC_1_EN			(0x1 << 15)
+#define RT5660_DMIC_1L_LH_MASK			(0x1 << 13)
+#define RT5660_DMIC_1L_LH_SFT			13
+#define RT5660_DMIC_1L_LH_RISING		(0x0 << 13)
+#define RT5660_DMIC_1L_LH_FALLING		(0x1 << 13)
+#define RT5660_DMIC_1R_LH_MASK			(0x1 << 12)
+#define RT5660_DMIC_1R_LH_SFT			12
+#define RT5660_DMIC_1R_LH_RISING		(0x0 << 12)
+#define RT5660_DMIC_1R_LH_FALLING		(0x1 << 12)
+#define RT5660_SEL_DMIC_DATA_MASK		(0x1 << 11)
+#define RT5660_SEL_DMIC_DATA_SFT		11
+#define RT5660_SEL_DMIC_DATA_GPIO2		(0x0 << 11)
+#define RT5660_SEL_DMIC_DATA_IN1P		(0x1 << 11)
+#define RT5660_DMIC_CLK_MASK			(0x7 << 5)
+#define RT5660_DMIC_CLK_SFT			5
+
+/* Global Clock Control (0x80) */
+#define RT5660_SCLK_SRC_MASK			(0x3 << 14)
+#define RT5660_SCLK_SRC_SFT			14
+#define RT5660_SCLK_SRC_MCLK			(0x0 << 14)
+#define RT5660_SCLK_SRC_PLL1			(0x1 << 14)
+#define RT5660_SCLK_SRC_RCCLK			(0x2 << 14)
+#define RT5660_PLL1_SRC_MASK			(0x3 << 12)
+#define RT5660_PLL1_SRC_SFT			12
+#define RT5660_PLL1_SRC_MCLK			(0x0 << 12)
+#define RT5660_PLL1_SRC_BCLK1			(0x1 << 12)
+#define RT5660_PLL1_SRC_RCCLK			(0x2 << 12)
+#define RT5660_PLL1_PD_MASK			(0x1 << 3)
+#define RT5660_PLL1_PD_SFT			3
+#define RT5660_PLL1_PD_1			(0x0 << 3)
+#define RT5660_PLL1_PD_2			(0x1 << 3)
+
+#define RT5660_PLL_INP_MAX			40000000
+#define RT5660_PLL_INP_MIN			256000
+/* PLL M/N/K Code Control 1 (0x81) */
+#define RT5660_PLL_N_MAX			0x1ff
+#define RT5660_PLL_N_MASK			(RT5660_PLL_N_MAX << 7)
+#define RT5660_PLL_N_SFT			7
+#define RT5660_PLL_K_MAX			0x1f
+#define RT5660_PLL_K_MASK			(RT5660_PLL_K_MAX)
+#define RT5660_PLL_K_SFT			0
+
+/* PLL M/N/K Code Control 2 (0x82) */
+#define RT5660_PLL_M_MAX			0xf
+#define RT5660_PLL_M_MASK			(RT5660_PLL_M_MAX << 12)
+#define RT5660_PLL_M_SFT			12
+#define RT5660_PLL_M_BP				(0x1 << 11)
+#define RT5660_PLL_M_BP_SFT			11
+
+/* Class D Over Current Control (0x8c) */
+#define RT5660_CLSD_OC_MASK			(0x1 << 9)
+#define RT5660_CLSD_OC_SFT			9
+#define RT5660_CLSD_OC_PU			(0x0 << 9)
+#define RT5660_CLSD_OC_PD			(0x1 << 9)
+#define RT5660_AUTO_PD_MASK			(0x1 << 8)
+#define RT5660_AUTO_PD_SFT			8
+#define RT5660_AUTO_PD_DIS			(0x0 << 8)
+#define RT5660_AUTO_PD_EN			(0x1 << 8)
+#define RT5660_CLSD_OC_TH_MASK			(0x3f)
+#define RT5660_CLSD_OC_TH_SFT			0
+
+/* Class D Output Control (0x8d) */
+#define RT5660_CLSD_RATIO_MASK			(0xf << 12)
+#define RT5660_CLSD_RATIO_SFT			12
+
+/* Lout Amp Control 1 (0x8e) */
+#define RT5660_LOUT_CO_MASK			(0x1 << 4)
+#define RT5660_LOUT_CO_SFT			4
+#define RT5660_LOUT_CO_DIS			(0x0 << 4)
+#define RT5660_LOUT_CO_EN			(0x1 << 4)
+#define RT5660_LOUT_CB_MASK			(0x1)
+#define RT5660_LOUT_CB_SFT			0
+#define RT5660_LOUT_CB_PD			(0x0)
+#define RT5660_LOUT_CB_PU			(0x1)
+
+/* SPKVDD detection control (0x92) */
+#define RT5660_SPKVDD_DET_MASK			(0x1 << 15)
+#define RT5660_SPKVDD_DET_SFT			15
+#define RT5660_SPKVDD_DET_DIS			(0x0 << 15)
+#define RT5660_SPKVDD_DET_EN			(0x1 << 15)
+#define RT5660_SPK_AG_MASK			(0x1 << 14)
+#define RT5660_SPK_AG_SFT			14
+#define RT5660_SPK_AG_DIS			(0x0 << 14)
+#define RT5660_SPK_AG_EN			(0x1 << 14)
+
+/* Micbias Control (0x93) */
+#define RT5660_MIC1_BS_MASK			(0x1 << 15)
+#define RT5660_MIC1_BS_SFT			15
+#define RT5660_MIC1_BS_9AV			(0x0 << 15)
+#define RT5660_MIC1_BS_75AV			(0x1 << 15)
+#define RT5660_MIC2_BS_MASK			(0x1 << 14)
+#define RT5660_MIC2_BS_SFT			14
+#define RT5660_MIC2_BS_9AV			(0x0 << 14)
+#define RT5660_MIC2_BS_75AV			(0x1 << 14)
+#define RT5660_MIC1_OVCD_MASK			(0x1 << 11)
+#define RT5660_MIC1_OVCD_SFT			11
+#define RT5660_MIC1_OVCD_DIS			(0x0 << 11)
+#define RT5660_MIC1_OVCD_EN			(0x1 << 11)
+#define RT5660_MIC1_OVTH_MASK			(0x3 << 9)
+#define RT5660_MIC1_OVTH_SFT			9
+#define RT5660_MIC1_OVTH_600UA			(0x0 << 9)
+#define RT5660_MIC1_OVTH_1500UA			(0x1 << 9)
+#define RT5660_MIC1_OVTH_2000UA			(0x2 << 9)
+#define RT5660_MIC2_OVCD_MASK			(0x1 << 8)
+#define RT5660_MIC2_OVCD_SFT			8
+#define RT5660_MIC2_OVCD_DIS			(0x0 << 8)
+#define RT5660_MIC2_OVCD_EN			(0x1 << 8)
+#define RT5660_MIC2_OVTH_MASK			(0x3 << 6)
+#define RT5660_MIC2_OVTH_SFT			6
+#define RT5660_MIC2_OVTH_600UA			(0x0 << 6)
+#define RT5660_MIC2_OVTH_1500UA			(0x1 << 6)
+#define RT5660_MIC2_OVTH_2000UA			(0x2 << 6)
+#define RT5660_PWR_CLK25M_MASK			(0x1 << 4)
+#define RT5660_PWR_CLK25M_SFT			4
+#define RT5660_PWR_CLK25M_PD			(0x0 << 4)
+#define RT5660_PWR_CLK25M_PU			(0x1 << 4)
+
+/* EQ Control 1 (0xb0) */
+#define RT5660_EQ_SRC_MASK			(0x1 << 15)
+#define RT5660_EQ_SRC_SFT			15
+#define RT5660_EQ_SRC_DAC			(0x0 << 15)
+#define RT5660_EQ_SRC_ADC			(0x1 << 15)
+#define RT5660_EQ_UPD				(0x1 << 14)
+#define RT5660_EQ_UPD_BIT			14
+
+/* Jack Detect Control (0xbb) */
+#define RT5660_JD_MASK				(0x3 << 14)
+#define RT5660_JD_SFT				14
+#define RT5660_JD_DIS				(0x0 << 14)
+#define RT5660_JD_GPIO1				(0x1 << 14)
+#define RT5660_JD_GPIO2				(0x2 << 14)
+#define RT5660_JD_LOUT_MASK			(0x1 << 11)
+#define RT5660_JD_LOUT_SFT			11
+#define RT5660_JD_LOUT_DIS			(0x0 << 11)
+#define RT5660_JD_LOUT_EN			(0x1 << 11)
+#define RT5660_JD_LOUT_TRG_MASK			(0x1 << 10)
+#define RT5660_JD_LOUT_TRG_SFT			10
+#define RT5660_JD_LOUT_TRG_LO			(0x0 << 10)
+#define RT5660_JD_LOUT_TRG_HI			(0x1 << 10)
+#define RT5660_JD_SPO_MASK			(0x1 << 9)
+#define RT5660_JD_SPO_SFT			9
+#define RT5660_JD_SPO_DIS			(0x0 << 9)
+#define RT5660_JD_SPO_EN			(0x1 << 9)
+#define RT5660_JD_SPO_TRG_MASK			(0x1 << 8)
+#define RT5660_JD_SPO_TRG_SFT			8
+#define RT5660_JD_SPO_TRG_LO			(0x0 << 8)
+#define RT5660_JD_SPO_TRG_HI			(0x1 << 8)
+
+/* IRQ Control 1 (0xbd) */
+#define RT5660_IRQ_JD_MASK			(0x1 << 15)
+#define RT5660_IRQ_JD_SFT			15
+#define RT5660_IRQ_JD_BP			(0x0 << 15)
+#define RT5660_IRQ_JD_NOR			(0x1 << 15)
+#define RT5660_IRQ_OT_MASK			(0x1 << 14)
+#define RT5660_IRQ_OT_SFT			14
+#define RT5660_IRQ_OT_BP			(0x0 << 14)
+#define RT5660_IRQ_OT_NOR			(0x1 << 14)
+#define RT5660_JD_STKY_MASK			(0x1 << 13)
+#define RT5660_JD_STKY_SFT			13
+#define RT5660_JD_STKY_DIS			(0x0 << 13)
+#define RT5660_JD_STKY_EN			(0x1 << 13)
+#define RT5660_OT_STKY_MASK			(0x1 << 12)
+#define RT5660_OT_STKY_SFT			12
+#define RT5660_OT_STKY_DIS			(0x0 << 12)
+#define RT5660_OT_STKY_EN			(0x1 << 12)
+#define RT5660_JD_P_MASK			(0x1 << 11)
+#define RT5660_JD_P_SFT				11
+#define RT5660_JD_P_NOR				(0x0 << 11)
+#define RT5660_JD_P_INV				(0x1 << 11)
+#define RT5660_OT_P_MASK			(0x1 << 10)
+#define RT5660_OT_P_SFT				10
+#define RT5660_OT_P_NOR				(0x0 << 10)
+#define RT5660_OT_P_INV				(0x1 << 10)
+
+/* IRQ Control 2 (0xbe) */
+#define RT5660_IRQ_MB1_OC_MASK			(0x1 << 15)
+#define RT5660_IRQ_MB1_OC_SFT			15
+#define RT5660_IRQ_MB1_OC_BP			(0x0 << 15)
+#define RT5660_IRQ_MB1_OC_NOR			(0x1 << 15)
+#define RT5660_IRQ_MB2_OC_MASK			(0x1 << 14)
+#define RT5660_IRQ_MB2_OC_SFT			14
+#define RT5660_IRQ_MB2_OC_BP			(0x0 << 14)
+#define RT5660_IRQ_MB2_OC_NOR			(0x1 << 14)
+#define RT5660_MB1_OC_STKY_MASK			(0x1 << 11)
+#define RT5660_MB1_OC_STKY_SFT			11
+#define RT5660_MB1_OC_STKY_DIS			(0x0 << 11)
+#define RT5660_MB1_OC_STKY_EN			(0x1 << 11)
+#define RT5660_MB2_OC_STKY_MASK			(0x1 << 10)
+#define RT5660_MB2_OC_STKY_SFT			10
+#define RT5660_MB2_OC_STKY_DIS			(0x0 << 10)
+#define RT5660_MB2_OC_STKY_EN			(0x1 << 10)
+#define RT5660_MB1_OC_P_MASK			(0x1 << 7)
+#define RT5660_MB1_OC_P_SFT			7
+#define RT5660_MB1_OC_P_NOR			(0x0 << 7)
+#define RT5660_MB1_OC_P_INV			(0x1 << 7)
+#define RT5660_MB2_OC_P_MASK			(0x1 << 6)
+#define RT5660_MB2_OC_P_SFT			6
+#define RT5660_MB2_OC_P_NOR			(0x0 << 6)
+#define RT5660_MB2_OC_P_INV			(0x1 << 6)
+#define RT5660_MB1_OC_CLR			(0x1 << 3)
+#define RT5660_MB1_OC_CLR_SFT			3
+#define RT5660_MB2_OC_CLR			(0x1 << 2)
+#define RT5660_MB2_OC_CLR_SFT			2
+
+/* GPIO Control 1 (0xc0) */
+#define RT5660_GP2_PIN_MASK			(0x1 << 14)
+#define RT5660_GP2_PIN_SFT			14
+#define RT5660_GP2_PIN_GPIO2			(0x0 << 14)
+#define RT5660_GP2_PIN_DMIC1_SDA		(0x1 << 14)
+#define RT5660_GP1_PIN_MASK			(0x3 << 12)
+#define RT5660_GP1_PIN_SFT			12
+#define RT5660_GP1_PIN_GPIO1			(0x0 << 12)
+#define RT5660_GP1_PIN_DMIC1_SCL		(0x1 << 12)
+#define RT5660_GP1_PIN_IRQ			(0x2 << 12)
+#define RT5660_GPIO_M_MASK			(0x1 << 9)
+#define RT5660_GPIO_M_SFT			9
+#define RT5660_GPIO_M_FLT			(0x0 << 9)
+#define RT5660_GPIO_M_PH			(0x1 << 9)
+
+/* GPIO Control 3 (0xc2) */
+#define RT5660_GP2_PF_MASK			(0x1 << 5)
+#define RT5660_GP2_PF_SFT			5
+#define RT5660_GP2_PF_IN			(0x0 << 5)
+#define RT5660_GP2_PF_OUT			(0x1 << 5)
+#define RT5660_GP2_OUT_MASK			(0x1 << 4)
+#define RT5660_GP2_OUT_SFT			4
+#define RT5660_GP2_OUT_LO			(0x0 << 4)
+#define RT5660_GP2_OUT_HI			(0x1 << 4)
+#define RT5660_GP2_P_MASK			(0x1 << 3)
+#define RT5660_GP2_P_SFT			3
+#define RT5660_GP2_P_NOR			(0x0 << 3)
+#define RT5660_GP2_P_INV			(0x1 << 3)
+#define RT5660_GP1_PF_MASK			(0x1 << 2)
+#define RT5660_GP1_PF_SFT			2
+#define RT5660_GP1_PF_IN			(0x0 << 2)
+#define RT5660_GP1_PF_OUT			(0x1 << 2)
+#define RT5660_GP1_OUT_MASK			(0x1 << 1)
+#define RT5660_GP1_OUT_SFT			1
+#define RT5660_GP1_OUT_LO			(0x0 << 1)
+#define RT5660_GP1_OUT_HI			(0x1 << 1)
+#define RT5660_GP1_P_MASK			(0x1)
+#define RT5660_GP1_P_SFT			0
+#define RT5660_GP1_P_NOR			(0x0)
+#define RT5660_GP1_P_INV			(0x1)
+
+/* Soft volume and zero cross control 1 (0xd9) */
+#define RT5660_SV_MASK				(0x1 << 15)
+#define RT5660_SV_SFT				15
+#define RT5660_SV_DIS				(0x0 << 15)
+#define RT5660_SV_EN				(0x1 << 15)
+#define RT5660_SPO_SV_MASK			(0x1 << 14)
+#define RT5660_SPO_SV_SFT			14
+#define RT5660_SPO_SV_DIS			(0x0 << 14)
+#define RT5660_SPO_SV_EN			(0x1 << 14)
+#define RT5660_OUT_SV_MASK			(0x1 << 12)
+#define RT5660_OUT_SV_SFT			12
+#define RT5660_OUT_SV_DIS			(0x0 << 12)
+#define RT5660_OUT_SV_EN			(0x1 << 12)
+#define RT5660_ZCD_DIG_MASK			(0x1 << 11)
+#define RT5660_ZCD_DIG_SFT			11
+#define RT5660_ZCD_DIG_DIS			(0x0 << 11)
+#define RT5660_ZCD_DIG_EN			(0x1 << 11)
+#define RT5660_ZCD_MASK				(0x1 << 10)
+#define RT5660_ZCD_SFT				10
+#define RT5660_ZCD_PD				(0x0 << 10)
+#define RT5660_ZCD_PU				(0x1 << 10)
+#define RT5660_SV_DLY_MASK			(0xf)
+#define RT5660_SV_DLY_SFT			0
+
+/* Soft volume and zero cross control 2 (0xda) */
+#define RT5660_ZCD_SPO_MASK			(0x1 << 15)
+#define RT5660_ZCD_SPO_SFT			15
+#define RT5660_ZCD_SPO_DIS			(0x0 << 15)
+#define RT5660_ZCD_SPO_EN			(0x1 << 15)
+#define RT5660_ZCD_OMR_MASK			(0x1 << 8)
+#define RT5660_ZCD_OMR_SFT			8
+#define RT5660_ZCD_OMR_DIS			(0x0 << 8)
+#define RT5660_ZCD_OMR_EN			(0x1 << 8)
+#define RT5660_ZCD_OML_MASK			(0x1 << 7)
+#define RT5660_ZCD_OML_SFT			7
+#define RT5660_ZCD_OML_DIS			(0x0 << 7)
+#define RT5660_ZCD_OML_EN			(0x1 << 7)
+#define RT5660_ZCD_SPM_MASK			(0x1 << 6)
+#define RT5660_ZCD_SPM_SFT			6
+#define RT5660_ZCD_SPM_DIS			(0x0 << 6)
+#define RT5660_ZCD_SPM_EN			(0x1 << 6)
+#define RT5660_ZCD_RMR_MASK			(0x1 << 5)
+#define RT5660_ZCD_RMR_SFT			5
+#define RT5660_ZCD_RMR_DIS			(0x0 << 5)
+#define RT5660_ZCD_RMR_EN			(0x1 << 5)
+#define RT5660_ZCD_RML_MASK			(0x1 << 4)
+#define RT5660_ZCD_RML_SFT			4
+#define RT5660_ZCD_RML_DIS			(0x0 << 4)
+#define RT5660_ZCD_RML_EN			(0x1 << 4)
+
+/* General Control 1 (0xfa) */
+#define RT5660_PWR_VREF_HP			(0x1 << 11)
+#define RT5660_PWR_VREF_HP_SFT			11
+#define RT5660_DIG_GATE_CTRL			(0x1)
+#define RT5660_DIG_GATE_CTRL_SFT		0
+
+/* System Clock Source */
+#define RT5660_SCLK_S_MCLK			0
+#define RT5660_SCLK_S_PLL1			1
+#define RT5660_SCLK_S_RCCLK			2
+
+/* PLL1 Source */
+#define RT5660_PLL1_S_MCLK			0
+#define RT5660_PLL1_S_BCLK			1
+
+enum {
+	RT5660_AIF1,
+	RT5660_AIFS,
+};
+
+struct rt5660_priv {
+	struct snd_soc_codec *codec;
+	struct rt5660_platform_data pdata;
+	struct regmap *regmap;
+	struct clk *mclk;
+
+	int sysclk;
+	int sysclk_src;
+	int lrck[RT5660_AIFS];
+	int bclk[RT5660_AIFS];
+	int master[RT5660_AIFS];
+
+	int pll_src;
+	int pll_in;
+	int pll_out;
+};
+
+#endif
diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c
new file mode 100644
index 0000000..01a18d8
--- /dev/null
+++ b/sound/soc/codecs/rt5663.c
@@ -0,0 +1,3218 @@
+/*
+ * rt5663.c  --  RT5668/RT5663 ALSA SoC audio codec driver
+ *
+ * Copyright 2016 Realtek Semiconductor Corp.
+ * Author: Jack Yu <jack.yu@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.h>
+#include <linux/workqueue.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rt5663.h"
+#include "rl6231.h"
+
+#define RT5668_DEVICE_ID 0x6451
+#define RT5663_DEVICE_ID 0x6406
+
+enum {
+	CODEC_TYPE_RT5668,
+	CODEC_TYPE_RT5663,
+};
+
+struct rt5663_priv {
+	struct snd_soc_codec *codec;
+	struct regmap *regmap;
+	struct delayed_work jack_detect_work;
+	struct snd_soc_jack *hs_jack;
+	struct timer_list btn_check_timer;
+
+	int codec_type;
+	int sysclk;
+	int sysclk_src;
+	int lrck;
+
+	int pll_src;
+	int pll_in;
+	int pll_out;
+
+	int jack_type;
+};
+
+static const struct reg_default rt5668_reg[] = {
+	{ 0x0000, 0x0000 },
+	{ 0x0001, 0xc8c8 },
+	{ 0x0002, 0x8080 },
+	{ 0x0003, 0x8000 },
+	{ 0x0004, 0xc80a },
+	{ 0x0005, 0x0000 },
+	{ 0x0006, 0x0000 },
+	{ 0x0007, 0x0000 },
+	{ 0x000a, 0x0000 },
+	{ 0x000b, 0x0000 },
+	{ 0x000c, 0x0000 },
+	{ 0x000d, 0x0000 },
+	{ 0x000f, 0x0808 },
+	{ 0x0010, 0x4000 },
+	{ 0x0011, 0x0000 },
+	{ 0x0012, 0x1404 },
+	{ 0x0013, 0x1000 },
+	{ 0x0014, 0xa00a },
+	{ 0x0015, 0x0404 },
+	{ 0x0016, 0x0404 },
+	{ 0x0017, 0x0011 },
+	{ 0x0018, 0xafaf },
+	{ 0x0019, 0xafaf },
+	{ 0x001a, 0xafaf },
+	{ 0x001b, 0x0011 },
+	{ 0x001c, 0x2f2f },
+	{ 0x001d, 0x2f2f },
+	{ 0x001e, 0x2f2f },
+	{ 0x001f, 0x0000 },
+	{ 0x0020, 0x0000 },
+	{ 0x0021, 0x0000 },
+	{ 0x0022, 0x5757 },
+	{ 0x0023, 0x0039 },
+	{ 0x0024, 0x000b },
+	{ 0x0026, 0xc0c0 },
+	{ 0x0027, 0xc0c0 },
+	{ 0x0028, 0xc0c0 },
+	{ 0x0029, 0x8080 },
+	{ 0x002a, 0xaaaa },
+	{ 0x002b, 0xaaaa },
+	{ 0x002c, 0xaba8 },
+	{ 0x002d, 0x0000 },
+	{ 0x002e, 0x0000 },
+	{ 0x002f, 0x0000 },
+	{ 0x0030, 0x0000 },
+	{ 0x0031, 0x5000 },
+	{ 0x0032, 0x0000 },
+	{ 0x0033, 0x0000 },
+	{ 0x0034, 0x0000 },
+	{ 0x0035, 0x0000 },
+	{ 0x003a, 0x0000 },
+	{ 0x003b, 0x0000 },
+	{ 0x003c, 0x00ff },
+	{ 0x003d, 0x0000 },
+	{ 0x003e, 0x00ff },
+	{ 0x003f, 0x0000 },
+	{ 0x0040, 0x0000 },
+	{ 0x0041, 0x00ff },
+	{ 0x0042, 0x0000 },
+	{ 0x0043, 0x00ff },
+	{ 0x0044, 0x0c0c },
+	{ 0x0049, 0xc00b },
+	{ 0x004a, 0x0000 },
+	{ 0x004b, 0x031f },
+	{ 0x004d, 0x0000 },
+	{ 0x004e, 0x001f },
+	{ 0x004f, 0x0000 },
+	{ 0x0050, 0x001f },
+	{ 0x0052, 0xf000 },
+	{ 0x0061, 0x0000 },
+	{ 0x0062, 0x0000 },
+	{ 0x0063, 0x003e },
+	{ 0x0064, 0x0000 },
+	{ 0x0065, 0x0000 },
+	{ 0x0066, 0x003f },
+	{ 0x0067, 0x0000 },
+	{ 0x006b, 0x0000 },
+	{ 0x006d, 0xff00 },
+	{ 0x006e, 0x2808 },
+	{ 0x006f, 0x000a },
+	{ 0x0070, 0x8000 },
+	{ 0x0071, 0x8000 },
+	{ 0x0072, 0x8000 },
+	{ 0x0073, 0x7000 },
+	{ 0x0074, 0x7770 },
+	{ 0x0075, 0x0002 },
+	{ 0x0076, 0x0001 },
+	{ 0x0078, 0x00f0 },
+	{ 0x0079, 0x0000 },
+	{ 0x007a, 0x0000 },
+	{ 0x007b, 0x0000 },
+	{ 0x007c, 0x0000 },
+	{ 0x007d, 0x0123 },
+	{ 0x007e, 0x4500 },
+	{ 0x007f, 0x8003 },
+	{ 0x0080, 0x0000 },
+	{ 0x0081, 0x0000 },
+	{ 0x0082, 0x0000 },
+	{ 0x0083, 0x0000 },
+	{ 0x0084, 0x0000 },
+	{ 0x0085, 0x0000 },
+	{ 0x0086, 0x0008 },
+	{ 0x0087, 0x0000 },
+	{ 0x0088, 0x0000 },
+	{ 0x0089, 0x0000 },
+	{ 0x008a, 0x0000 },
+	{ 0x008b, 0x0000 },
+	{ 0x008c, 0x0003 },
+	{ 0x008e, 0x0060 },
+	{ 0x008f, 0x1000 },
+	{ 0x0091, 0x0c26 },
+	{ 0x0092, 0x0073 },
+	{ 0x0093, 0x0000 },
+	{ 0x0094, 0x0080 },
+	{ 0x0098, 0x0000 },
+	{ 0x0099, 0x0000 },
+	{ 0x009a, 0x0007 },
+	{ 0x009f, 0x0000 },
+	{ 0x00a0, 0x0000 },
+	{ 0x00a1, 0x0002 },
+	{ 0x00a2, 0x0001 },
+	{ 0x00a3, 0x0002 },
+	{ 0x00a4, 0x0001 },
+	{ 0x00ae, 0x2040 },
+	{ 0x00af, 0x0000 },
+	{ 0x00b6, 0x0000 },
+	{ 0x00b7, 0x0000 },
+	{ 0x00b8, 0x0000 },
+	{ 0x00b9, 0x0000 },
+	{ 0x00ba, 0x0002 },
+	{ 0x00bb, 0x0000 },
+	{ 0x00be, 0x0000 },
+	{ 0x00c0, 0x0000 },
+	{ 0x00c1, 0x0aaa },
+	{ 0x00c2, 0xaa80 },
+	{ 0x00c3, 0x0003 },
+	{ 0x00c4, 0x0000 },
+	{ 0x00d0, 0x0000 },
+	{ 0x00d1, 0x2244 },
+	{ 0x00d2, 0x0000 },
+	{ 0x00d3, 0x3300 },
+	{ 0x00d4, 0x2200 },
+	{ 0x00d9, 0x0809 },
+	{ 0x00da, 0x0000 },
+	{ 0x00db, 0x0008 },
+	{ 0x00dc, 0x00c0 },
+	{ 0x00dd, 0x6724 },
+	{ 0x00de, 0x3131 },
+	{ 0x00df, 0x0008 },
+	{ 0x00e0, 0x4000 },
+	{ 0x00e1, 0x3131 },
+	{ 0x00e2, 0x600c },
+	{ 0x00ea, 0xb320 },
+	{ 0x00eb, 0x0000 },
+	{ 0x00ec, 0xb300 },
+	{ 0x00ed, 0x0000 },
+	{ 0x00ee, 0xb320 },
+	{ 0x00ef, 0x0000 },
+	{ 0x00f0, 0x0201 },
+	{ 0x00f1, 0x0ddd },
+	{ 0x00f2, 0x0ddd },
+	{ 0x00f6, 0x0000 },
+	{ 0x00f7, 0x0000 },
+	{ 0x00f8, 0x0000 },
+	{ 0x00fa, 0x0000 },
+	{ 0x00fb, 0x0000 },
+	{ 0x00fc, 0x0000 },
+	{ 0x00fd, 0x0000 },
+	{ 0x00fe, 0x10ec },
+	{ 0x00ff, 0x6451 },
+	{ 0x0100, 0xaaaa },
+	{ 0x0101, 0x000a },
+	{ 0x010a, 0xaaaa },
+	{ 0x010b, 0xa0a0 },
+	{ 0x010c, 0xaeae },
+	{ 0x010d, 0xaaaa },
+	{ 0x010e, 0xaaaa },
+	{ 0x010f, 0xaaaa },
+	{ 0x0110, 0xe002 },
+	{ 0x0111, 0xa602 },
+	{ 0x0112, 0xaaaa },
+	{ 0x0113, 0x2000 },
+	{ 0x0117, 0x0f00 },
+	{ 0x0125, 0x0420 },
+	{ 0x0132, 0x0000 },
+	{ 0x0133, 0x0000 },
+	{ 0x0136, 0x5555 },
+	{ 0x0137, 0x5540 },
+	{ 0x0138, 0x3700 },
+	{ 0x0139, 0x79a1 },
+	{ 0x013a, 0x2020 },
+	{ 0x013b, 0x2020 },
+	{ 0x013c, 0x2005 },
+	{ 0x013f, 0x0000 },
+	{ 0x0145, 0x0002 },
+	{ 0x0146, 0x0000 },
+	{ 0x0147, 0x0000 },
+	{ 0x0148, 0x0000 },
+	{ 0x0160, 0x4ec0 },
+	{ 0x0161, 0x0080 },
+	{ 0x0162, 0x0200 },
+	{ 0x0163, 0x0800 },
+	{ 0x0164, 0x0000 },
+	{ 0x0165, 0x0000 },
+	{ 0x0166, 0x0000 },
+	{ 0x0167, 0x000f },
+	{ 0x0168, 0x000f },
+	{ 0x0170, 0x4e80 },
+	{ 0x0171, 0x0080 },
+	{ 0x0172, 0x0200 },
+	{ 0x0173, 0x0800 },
+	{ 0x0174, 0x00ff },
+	{ 0x0175, 0x0000 },
+	{ 0x0190, 0x4131 },
+	{ 0x0191, 0x4131 },
+	{ 0x0192, 0x4131 },
+	{ 0x0193, 0x4131 },
+	{ 0x0194, 0x0000 },
+	{ 0x0195, 0x0000 },
+	{ 0x0196, 0x0000 },
+	{ 0x0197, 0x0000 },
+	{ 0x0198, 0x0000 },
+	{ 0x0199, 0x0000 },
+	{ 0x01a0, 0x1e64 },
+	{ 0x01a1, 0x06a3 },
+	{ 0x01a2, 0x0000 },
+	{ 0x01a3, 0x0000 },
+	{ 0x01a4, 0x0000 },
+	{ 0x01a5, 0x0000 },
+	{ 0x01a6, 0x0000 },
+	{ 0x01a7, 0x0000 },
+	{ 0x01a8, 0x0000 },
+	{ 0x01a9, 0x0000 },
+	{ 0x01aa, 0x0000 },
+	{ 0x01ab, 0x0000 },
+	{ 0x01b5, 0x0000 },
+	{ 0x01b6, 0x01c3 },
+	{ 0x01b7, 0x02a0 },
+	{ 0x01b8, 0x03e9 },
+	{ 0x01b9, 0x1389 },
+	{ 0x01ba, 0xc351 },
+	{ 0x01bb, 0x0009 },
+	{ 0x01bc, 0x0018 },
+	{ 0x01bd, 0x002a },
+	{ 0x01be, 0x004c },
+	{ 0x01bf, 0x0097 },
+	{ 0x01c0, 0x433d },
+	{ 0x01c1, 0x0000 },
+	{ 0x01c2, 0x0000 },
+	{ 0x01c3, 0x0000 },
+	{ 0x01c4, 0x0000 },
+	{ 0x01c5, 0x0000 },
+	{ 0x01c6, 0x0000 },
+	{ 0x01c7, 0x0000 },
+	{ 0x01c8, 0x40af },
+	{ 0x01c9, 0x0702 },
+	{ 0x01ca, 0x0000 },
+	{ 0x01cb, 0x0000 },
+	{ 0x01cc, 0x5757 },
+	{ 0x01cd, 0x5757 },
+	{ 0x01ce, 0x5757 },
+	{ 0x01cf, 0x5757 },
+	{ 0x01d0, 0x5757 },
+	{ 0x01d1, 0x5757 },
+	{ 0x01d2, 0x5757 },
+	{ 0x01d3, 0x5757 },
+	{ 0x01d4, 0x5757 },
+	{ 0x01d5, 0x5757 },
+	{ 0x01d6, 0x003c },
+	{ 0x01da, 0x0000 },
+	{ 0x01db, 0x0000 },
+	{ 0x01dc, 0x0000 },
+	{ 0x01de, 0x7c00 },
+	{ 0x01df, 0x0320 },
+	{ 0x01e0, 0x06a1 },
+	{ 0x01e1, 0x0000 },
+	{ 0x01e2, 0x0000 },
+	{ 0x01e3, 0x0000 },
+	{ 0x01e4, 0x0000 },
+	{ 0x01e5, 0x0000 },
+	{ 0x01e6, 0x0001 },
+	{ 0x01e7, 0x0000 },
+	{ 0x01e8, 0x0000 },
+	{ 0x01ea, 0x0000 },
+	{ 0x01eb, 0x0000 },
+	{ 0x01ec, 0x0000 },
+	{ 0x01ed, 0x0000 },
+	{ 0x01ee, 0x0000 },
+	{ 0x01ef, 0x0000 },
+	{ 0x01f0, 0x0000 },
+	{ 0x01f1, 0x0000 },
+	{ 0x01f2, 0x0000 },
+	{ 0x01f3, 0x0000 },
+	{ 0x01f4, 0x0000 },
+	{ 0x0200, 0x0000 },
+	{ 0x0201, 0x0000 },
+	{ 0x0202, 0x0000 },
+	{ 0x0203, 0x0000 },
+	{ 0x0204, 0x0000 },
+	{ 0x0205, 0x0000 },
+	{ 0x0206, 0x0000 },
+	{ 0x0207, 0x0000 },
+	{ 0x0208, 0x0000 },
+	{ 0x0210, 0x60b1 },
+	{ 0x0211, 0xa000 },
+	{ 0x0212, 0x024c },
+	{ 0x0213, 0xf7ff },
+	{ 0x0214, 0x024c },
+	{ 0x0215, 0x0102 },
+	{ 0x0216, 0x00a3 },
+	{ 0x0217, 0x0048 },
+	{ 0x0218, 0x92c0 },
+	{ 0x0219, 0x0000 },
+	{ 0x021a, 0x00c8 },
+	{ 0x021b, 0x0020 },
+	{ 0x02fa, 0x0000 },
+	{ 0x02fb, 0x0000 },
+	{ 0x02fc, 0x0000 },
+	{ 0x02ff, 0x0110 },
+	{ 0x0300, 0x001f },
+	{ 0x0301, 0x032c },
+	{ 0x0302, 0x5f21 },
+	{ 0x0303, 0x4000 },
+	{ 0x0304, 0x4000 },
+	{ 0x0305, 0x06d5 },
+	{ 0x0306, 0x8000 },
+	{ 0x0307, 0x0700 },
+	{ 0x0310, 0x4560 },
+	{ 0x0311, 0xa4a8 },
+	{ 0x0312, 0x7418 },
+	{ 0x0313, 0x0000 },
+	{ 0x0314, 0x0006 },
+	{ 0x0315, 0xffff },
+	{ 0x0316, 0xc400 },
+	{ 0x0317, 0x0000 },
+	{ 0x0330, 0x00a6 },
+	{ 0x0331, 0x04c3 },
+	{ 0x0332, 0x27c8 },
+	{ 0x0333, 0xbf50 },
+	{ 0x0334, 0x0045 },
+	{ 0x0335, 0x0007 },
+	{ 0x0336, 0x7418 },
+	{ 0x0337, 0x0501 },
+	{ 0x0338, 0x0000 },
+	{ 0x0339, 0x0010 },
+	{ 0x033a, 0x1010 },
+	{ 0x03c0, 0x7e00 },
+	{ 0x03c1, 0x8000 },
+	{ 0x03c2, 0x8000 },
+	{ 0x03c3, 0x8000 },
+	{ 0x03c4, 0x8000 },
+	{ 0x03c5, 0x8000 },
+	{ 0x03c6, 0x8000 },
+	{ 0x03c7, 0x8000 },
+	{ 0x03c8, 0x8000 },
+	{ 0x03c9, 0x8000 },
+	{ 0x03ca, 0x8000 },
+	{ 0x03cb, 0x8000 },
+	{ 0x03cc, 0x8000 },
+	{ 0x03d0, 0x0000 },
+	{ 0x03d1, 0x0000 },
+	{ 0x03d2, 0x0000 },
+	{ 0x03d3, 0x0000 },
+	{ 0x03d4, 0x2000 },
+	{ 0x03d5, 0x2000 },
+	{ 0x03d6, 0x0000 },
+	{ 0x03d7, 0x0000 },
+	{ 0x03d8, 0x2000 },
+	{ 0x03d9, 0x2000 },
+	{ 0x03da, 0x2000 },
+	{ 0x03db, 0x2000 },
+	{ 0x03dc, 0x0000 },
+	{ 0x03dd, 0x0000 },
+	{ 0x03de, 0x0000 },
+	{ 0x03df, 0x2000 },
+	{ 0x03e0, 0x0000 },
+	{ 0x03e1, 0x0000 },
+	{ 0x03e2, 0x0000 },
+	{ 0x03e3, 0x0000 },
+	{ 0x03e4, 0x0000 },
+	{ 0x03e5, 0x0000 },
+	{ 0x03e6, 0x0000 },
+	{ 0x03e7, 0x0000 },
+	{ 0x03e8, 0x0000 },
+	{ 0x03e9, 0x0000 },
+	{ 0x03ea, 0x0000 },
+	{ 0x03eb, 0x0000 },
+	{ 0x03ec, 0x0000 },
+	{ 0x03ed, 0x0000 },
+	{ 0x03ee, 0x0000 },
+	{ 0x03ef, 0x0000 },
+	{ 0x03f0, 0x0800 },
+	{ 0x03f1, 0x0800 },
+	{ 0x03f2, 0x0800 },
+	{ 0x03f3, 0x0800 },
+	{ 0x03fe, 0x0000 },
+	{ 0x03ff, 0x0000 },
+	{ 0x07f0, 0x0000 },
+	{ 0x07fa, 0x0000 },
+};
+
+static const struct reg_default rt5663_reg[] = {
+	{ 0x0000, 0x0000 },
+	{ 0x0002, 0x0008 },
+	{ 0x0005, 0x1000 },
+	{ 0x0006, 0x1000 },
+	{ 0x000a, 0x0000 },
+	{ 0x0010, 0x000f },
+	{ 0x0015, 0x42c1 },
+	{ 0x0016, 0x0000 },
+	{ 0x0018, 0x000b },
+	{ 0x0019, 0xafaf },
+	{ 0x001c, 0x2f2f },
+	{ 0x001f, 0x0000 },
+	{ 0x0022, 0x5757 },
+	{ 0x0023, 0x0039 },
+	{ 0x0026, 0xc0c0 },
+	{ 0x0029, 0x8080 },
+	{ 0x002a, 0xa0a0 },
+	{ 0x002c, 0x000c },
+	{ 0x002d, 0x0000 },
+	{ 0x0040, 0x0808 },
+	{ 0x0061, 0x0000 },
+	{ 0x0062, 0x0000 },
+	{ 0x0063, 0x003e },
+	{ 0x0064, 0x0000 },
+	{ 0x0065, 0x0000 },
+	{ 0x0066, 0x0000 },
+	{ 0x006b, 0x0000 },
+	{ 0x006e, 0x0000 },
+	{ 0x006f, 0x0000 },
+	{ 0x0070, 0x8020 },
+	{ 0x0073, 0x1000 },
+	{ 0x0074, 0xe400 },
+	{ 0x0075, 0x0002 },
+	{ 0x0076, 0x0001 },
+	{ 0x0077, 0x00f0 },
+	{ 0x0078, 0x0000 },
+	{ 0x0079, 0x0000 },
+	{ 0x007a, 0x0123 },
+	{ 0x007b, 0x8003 },
+	{ 0x0080, 0x0000 },
+	{ 0x0081, 0x0000 },
+	{ 0x0082, 0x0000 },
+	{ 0x0083, 0x0000 },
+	{ 0x0084, 0x0000 },
+	{ 0x0086, 0x0008 },
+	{ 0x0087, 0x0000 },
+	{ 0x008a, 0x0000 },
+	{ 0x008b, 0x0000 },
+	{ 0x008c, 0x0003 },
+	{ 0x008e, 0x0004 },
+	{ 0x008f, 0x1000 },
+	{ 0x0090, 0x0646 },
+	{ 0x0091, 0x0e3e },
+	{ 0x0092, 0x1071 },
+	{ 0x0093, 0x0000 },
+	{ 0x0094, 0x0080 },
+	{ 0x0097, 0x0000 },
+	{ 0x0098, 0x0000 },
+	{ 0x009a, 0x0000 },
+	{ 0x009f, 0x0000 },
+	{ 0x00ae, 0x2000 },
+	{ 0x00af, 0x0000 },
+	{ 0x00b6, 0x0000 },
+	{ 0x00b7, 0x0000 },
+	{ 0x00b8, 0x0000 },
+	{ 0x00ba, 0x0000 },
+	{ 0x00bb, 0x0000 },
+	{ 0x00be, 0x0000 },
+	{ 0x00bf, 0x0000 },
+	{ 0x00c0, 0x0000 },
+	{ 0x00c1, 0x0000 },
+	{ 0x00c5, 0x0000 },
+	{ 0x00cb, 0xa02f },
+	{ 0x00cc, 0x0000 },
+	{ 0x00cd, 0x0e02 },
+	{ 0x00d9, 0x08f9 },
+	{ 0x00db, 0x0008 },
+	{ 0x00dc, 0x00c0 },
+	{ 0x00dd, 0x6724 },
+	{ 0x00de, 0x3131 },
+	{ 0x00df, 0x0008 },
+	{ 0x00e0, 0x4000 },
+	{ 0x00e1, 0x3131 },
+	{ 0x00e2, 0x0043 },
+	{ 0x00e4, 0x400b },
+	{ 0x00e5, 0x8031 },
+	{ 0x00e6, 0x3080 },
+	{ 0x00e7, 0x4100 },
+	{ 0x00e8, 0x1400 },
+	{ 0x00e9, 0xe00a },
+	{ 0x00ea, 0x0404 },
+	{ 0x00eb, 0x0404 },
+	{ 0x00ec, 0xb320 },
+	{ 0x00ed, 0x0000 },
+	{ 0x00f4, 0x0000 },
+	{ 0x00f6, 0x0000 },
+	{ 0x00f8, 0x0000 },
+	{ 0x00fa, 0x8000 },
+	{ 0x00fd, 0x0001 },
+	{ 0x00fe, 0x10ec },
+	{ 0x00ff, 0x6406 },
+	{ 0x0100, 0xa0a0 },
+	{ 0x0108, 0x4444 },
+	{ 0x0109, 0x4444 },
+	{ 0x010a, 0xaaaa },
+	{ 0x010b, 0x00a0 },
+	{ 0x010c, 0x8aaa },
+	{ 0x010d, 0xaaaa },
+	{ 0x010e, 0x2aaa },
+	{ 0x010f, 0x002a },
+	{ 0x0110, 0xa0a4 },
+	{ 0x0111, 0x4602 },
+	{ 0x0112, 0x0101 },
+	{ 0x0113, 0x2000 },
+	{ 0x0114, 0x0000 },
+	{ 0x0116, 0x0000 },
+	{ 0x0117, 0x0f00 },
+	{ 0x0118, 0x0006 },
+	{ 0x0125, 0x2224 },
+	{ 0x0126, 0x5550 },
+	{ 0x0127, 0x0400 },
+	{ 0x0128, 0x7711 },
+	{ 0x0132, 0x0004 },
+	{ 0x0137, 0x5441 },
+	{ 0x0139, 0x79a1 },
+	{ 0x013a, 0x30c0 },
+	{ 0x013b, 0x2000 },
+	{ 0x013c, 0x2005 },
+	{ 0x013d, 0x30c0 },
+	{ 0x013e, 0x0000 },
+	{ 0x0140, 0x3700 },
+	{ 0x0141, 0x1f00 },
+	{ 0x0144, 0x0000 },
+	{ 0x0145, 0x0002 },
+	{ 0x0146, 0x0000 },
+	{ 0x0160, 0x0e80 },
+	{ 0x0161, 0x0020 },
+	{ 0x0162, 0x0080 },
+	{ 0x0163, 0x0800 },
+	{ 0x0164, 0x0000 },
+	{ 0x0165, 0x0000 },
+	{ 0x0166, 0x0000 },
+	{ 0x0167, 0x1417 },
+	{ 0x0168, 0x0017 },
+	{ 0x0169, 0x0017 },
+	{ 0x0180, 0x2000 },
+	{ 0x0181, 0x0000 },
+	{ 0x0182, 0x0000 },
+	{ 0x0183, 0x2000 },
+	{ 0x0184, 0x0000 },
+	{ 0x0185, 0x0000 },
+	{ 0x01b0, 0x4b30 },
+	{ 0x01b1, 0x0000 },
+	{ 0x01b2, 0xd870 },
+	{ 0x01b3, 0x0000 },
+	{ 0x01b4, 0x0030 },
+	{ 0x01b5, 0x5757 },
+	{ 0x01b6, 0x5757 },
+	{ 0x01b7, 0x5757 },
+	{ 0x01b8, 0x5757 },
+	{ 0x01c0, 0x433d },
+	{ 0x01c1, 0x0540 },
+	{ 0x01c2, 0x0000 },
+	{ 0x01c3, 0x0000 },
+	{ 0x01c4, 0x0000 },
+	{ 0x01c5, 0x0009 },
+	{ 0x01c6, 0x0018 },
+	{ 0x01c7, 0x002a },
+	{ 0x01c8, 0x004c },
+	{ 0x01c9, 0x0097 },
+	{ 0x01ca, 0x01c3 },
+	{ 0x01cb, 0x03e9 },
+	{ 0x01cc, 0x1389 },
+	{ 0x01cd, 0xc351 },
+	{ 0x01ce, 0x0000 },
+	{ 0x01cf, 0x0000 },
+	{ 0x01d0, 0x0000 },
+	{ 0x01d1, 0x0000 },
+	{ 0x01d2, 0x0000 },
+	{ 0x01d3, 0x003c },
+	{ 0x01d4, 0x5757 },
+	{ 0x01d5, 0x5757 },
+	{ 0x01d6, 0x5757 },
+	{ 0x01d7, 0x5757 },
+	{ 0x01d8, 0x5757 },
+	{ 0x01d9, 0x5757 },
+	{ 0x01da, 0x0000 },
+	{ 0x01db, 0x0000 },
+	{ 0x01dd, 0x0009 },
+	{ 0x01de, 0x7f00 },
+	{ 0x01df, 0x00c8 },
+	{ 0x01e0, 0x0691 },
+	{ 0x01e1, 0x0000 },
+	{ 0x01e2, 0x0000 },
+	{ 0x01e3, 0x0000 },
+	{ 0x01e4, 0x0000 },
+	{ 0x01e5, 0x0040 },
+	{ 0x01e6, 0x0000 },
+	{ 0x01e7, 0x0000 },
+	{ 0x01e8, 0x0000 },
+	{ 0x01ea, 0x0000 },
+	{ 0x01eb, 0x0000 },
+	{ 0x01ec, 0x0000 },
+	{ 0x01ed, 0x0000 },
+	{ 0x01ee, 0x0000 },
+	{ 0x01ef, 0x0000 },
+	{ 0x01f0, 0x0000 },
+	{ 0x01f1, 0x0000 },
+	{ 0x01f2, 0x0000 },
+	{ 0x0200, 0x0000 },
+	{ 0x0201, 0x2244 },
+	{ 0x0202, 0xaaaa },
+	{ 0x0250, 0x8010 },
+	{ 0x0251, 0x0000 },
+	{ 0x0252, 0x028a },
+	{ 0x02fa, 0x0000 },
+	{ 0x02fb, 0x0000 },
+	{ 0x02fc, 0x0000 },
+	{ 0x0300, 0x0000 },
+	{ 0x03d0, 0x0000 },
+	{ 0x03d1, 0x0000 },
+	{ 0x03d2, 0x0000 },
+	{ 0x03d3, 0x0000 },
+	{ 0x03d4, 0x2000 },
+	{ 0x03d5, 0x2000 },
+	{ 0x03d6, 0x0000 },
+	{ 0x03d7, 0x0000 },
+	{ 0x03d8, 0x2000 },
+	{ 0x03d9, 0x2000 },
+	{ 0x03da, 0x2000 },
+	{ 0x03db, 0x2000 },
+	{ 0x03dc, 0x0000 },
+	{ 0x03dd, 0x0000 },
+	{ 0x03de, 0x0000 },
+	{ 0x03df, 0x2000 },
+	{ 0x03e0, 0x0000 },
+	{ 0x03e1, 0x0000 },
+	{ 0x03e2, 0x0000 },
+	{ 0x03e3, 0x0000 },
+	{ 0x03e4, 0x0000 },
+	{ 0x03e5, 0x0000 },
+	{ 0x03e6, 0x0000 },
+	{ 0x03e7, 0x0000 },
+	{ 0x03e8, 0x0000 },
+	{ 0x03e9, 0x0000 },
+	{ 0x03ea, 0x0000 },
+	{ 0x03eb, 0x0000 },
+	{ 0x03ec, 0x0000 },
+	{ 0x03ed, 0x0000 },
+	{ 0x03ee, 0x0000 },
+	{ 0x03ef, 0x0000 },
+	{ 0x03f0, 0x0800 },
+	{ 0x03f1, 0x0800 },
+	{ 0x03f2, 0x0800 },
+	{ 0x03f3, 0x0800 },
+};
+
+static bool rt5663_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5663_RESET:
+	case RT5663_SIL_DET_CTL:
+	case RT5663_HP_IMP_GAIN_2:
+	case RT5663_AD_DA_MIXER:
+	case RT5663_FRAC_DIV_2:
+	case RT5663_MICBIAS_1:
+	case RT5663_ASRC_11_2:
+	case RT5663_ADC_EQ_1:
+	case RT5663_INT_ST_1:
+	case RT5663_INT_ST_2:
+	case RT5663_GPIO_STA:
+	case RT5663_SIN_GEN_1:
+	case RT5663_IL_CMD_1:
+	case RT5663_IL_CMD_5:
+	case RT5663_IL_CMD_PWRSAV1:
+	case RT5663_EM_JACK_TYPE_1:
+	case RT5663_EM_JACK_TYPE_2:
+	case RT5663_EM_JACK_TYPE_3:
+	case RT5663_JD_CTRL2:
+	case RT5663_VENDOR_ID:
+	case RT5663_VENDOR_ID_1:
+	case RT5663_VENDOR_ID_2:
+	case RT5663_PLL_INT_REG:
+	case RT5663_SOFT_RAMP:
+	case RT5663_STO_DRE_1:
+	case RT5663_STO_DRE_5:
+	case RT5663_STO_DRE_6:
+	case RT5663_STO_DRE_7:
+	case RT5663_MIC_DECRO_1:
+	case RT5663_MIC_DECRO_4:
+	case RT5663_HP_IMP_SEN_1:
+	case RT5663_HP_IMP_SEN_3:
+	case RT5663_HP_IMP_SEN_4:
+	case RT5663_HP_IMP_SEN_5:
+	case RT5663_HP_CALIB_1_1:
+	case RT5663_HP_CALIB_9:
+	case RT5663_HP_CALIB_ST1:
+	case RT5663_HP_CALIB_ST2:
+	case RT5663_HP_CALIB_ST3:
+	case RT5663_HP_CALIB_ST4:
+	case RT5663_HP_CALIB_ST5:
+	case RT5663_HP_CALIB_ST6:
+	case RT5663_HP_CALIB_ST7:
+	case RT5663_HP_CALIB_ST8:
+	case RT5663_HP_CALIB_ST9:
+	case RT5663_ANA_JD:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5663_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5663_RESET:
+	case RT5663_HP_OUT_EN:
+	case RT5663_HP_LCH_DRE:
+	case RT5663_HP_RCH_DRE:
+	case RT5663_CALIB_BST:
+	case RT5663_RECMIX:
+	case RT5663_SIL_DET_CTL:
+	case RT5663_PWR_SAV_SILDET:
+	case RT5663_SIDETONE_CTL:
+	case RT5663_STO1_DAC_DIG_VOL:
+	case RT5663_STO1_ADC_DIG_VOL:
+	case RT5663_STO1_BOOST:
+	case RT5663_HP_IMP_GAIN_1:
+	case RT5663_HP_IMP_GAIN_2:
+	case RT5663_STO1_ADC_MIXER:
+	case RT5663_AD_DA_MIXER:
+	case RT5663_STO_DAC_MIXER:
+	case RT5663_DIG_SIDE_MIXER:
+	case RT5663_BYPASS_STO_DAC:
+	case RT5663_CALIB_REC_MIX:
+	case RT5663_PWR_DIG_1:
+	case RT5663_PWR_DIG_2:
+	case RT5663_PWR_ANLG_1:
+	case RT5663_PWR_ANLG_2:
+	case RT5663_PWR_ANLG_3:
+	case RT5663_PWR_MIXER:
+	case RT5663_SIG_CLK_DET:
+	case RT5663_PRE_DIV_GATING_1:
+	case RT5663_PRE_DIV_GATING_2:
+	case RT5663_I2S1_SDP:
+	case RT5663_ADDA_CLK_1:
+	case RT5663_ADDA_RST:
+	case RT5663_FRAC_DIV_1:
+	case RT5663_FRAC_DIV_2:
+	case RT5663_TDM_1:
+	case RT5663_TDM_2:
+	case RT5663_TDM_3:
+	case RT5663_TDM_4:
+	case RT5663_TDM_5:
+	case RT5663_GLB_CLK:
+	case RT5663_PLL_1:
+	case RT5663_PLL_2:
+	case RT5663_ASRC_1:
+	case RT5663_ASRC_2:
+	case RT5663_ASRC_4:
+	case RT5663_DUMMY_REG:
+	case RT5663_ASRC_8:
+	case RT5663_ASRC_9:
+	case RT5663_ASRC_11:
+	case RT5663_DEPOP_1:
+	case RT5663_DEPOP_2:
+	case RT5663_DEPOP_3:
+	case RT5663_HP_CHARGE_PUMP_1:
+	case RT5663_HP_CHARGE_PUMP_2:
+	case RT5663_MICBIAS_1:
+	case RT5663_RC_CLK:
+	case RT5663_ASRC_11_2:
+	case RT5663_DUMMY_REG_2:
+	case RT5663_REC_PATH_GAIN:
+	case RT5663_AUTO_1MRC_CLK:
+	case RT5663_ADC_EQ_1:
+	case RT5663_ADC_EQ_2:
+	case RT5663_IRQ_1:
+	case RT5663_IRQ_2:
+	case RT5663_IRQ_3:
+	case RT5663_IRQ_4:
+	case RT5663_IRQ_5:
+	case RT5663_INT_ST_1:
+	case RT5663_INT_ST_2:
+	case RT5663_GPIO_1:
+	case RT5663_GPIO_2:
+	case RT5663_GPIO_STA:
+	case RT5663_SIN_GEN_1:
+	case RT5663_SIN_GEN_2:
+	case RT5663_SIN_GEN_3:
+	case RT5663_SOF_VOL_ZC1:
+	case RT5663_IL_CMD_1:
+	case RT5663_IL_CMD_2:
+	case RT5663_IL_CMD_3:
+	case RT5663_IL_CMD_4:
+	case RT5663_IL_CMD_5:
+	case RT5663_IL_CMD_6:
+	case RT5663_IL_CMD_7:
+	case RT5663_IL_CMD_8:
+	case RT5663_IL_CMD_PWRSAV1:
+	case RT5663_IL_CMD_PWRSAV2:
+	case RT5663_EM_JACK_TYPE_1:
+	case RT5663_EM_JACK_TYPE_2:
+	case RT5663_EM_JACK_TYPE_3:
+	case RT5663_EM_JACK_TYPE_4:
+	case RT5663_EM_JACK_TYPE_5:
+	case RT5663_EM_JACK_TYPE_6:
+	case RT5663_STO1_HPF_ADJ1:
+	case RT5663_STO1_HPF_ADJ2:
+	case RT5663_FAST_OFF_MICBIAS:
+	case RT5663_JD_CTRL1:
+	case RT5663_JD_CTRL2:
+	case RT5663_DIG_MISC:
+	case RT5663_VENDOR_ID:
+	case RT5663_VENDOR_ID_1:
+	case RT5663_VENDOR_ID_2:
+	case RT5663_DIG_VOL_ZCD:
+	case RT5663_ANA_BIAS_CUR_1:
+	case RT5663_ANA_BIAS_CUR_2:
+	case RT5663_ANA_BIAS_CUR_3:
+	case RT5663_ANA_BIAS_CUR_4:
+	case RT5663_ANA_BIAS_CUR_5:
+	case RT5663_ANA_BIAS_CUR_6:
+	case RT5663_BIAS_CUR_5:
+	case RT5663_BIAS_CUR_6:
+	case RT5663_BIAS_CUR_7:
+	case RT5663_BIAS_CUR_8:
+	case RT5663_DACREF_LDO:
+	case RT5663_DUMMY_REG_3:
+	case RT5663_BIAS_CUR_9:
+	case RT5663_DUMMY_REG_4:
+	case RT5663_VREFADJ_OP:
+	case RT5663_VREF_RECMIX:
+	case RT5663_CHARGE_PUMP_1:
+	case RT5663_CHARGE_PUMP_1_2:
+	case RT5663_CHARGE_PUMP_1_3:
+	case RT5663_CHARGE_PUMP_2:
+	case RT5663_DIG_IN_PIN1:
+	case RT5663_PAD_DRV_CTL:
+	case RT5663_PLL_INT_REG:
+	case RT5663_CHOP_DAC_L:
+	case RT5663_CHOP_ADC:
+	case RT5663_CALIB_ADC:
+	case RT5663_CHOP_DAC_R:
+	case RT5663_DUMMY_CTL_DACLR:
+	case RT5663_DUMMY_REG_5:
+	case RT5663_SOFT_RAMP:
+	case RT5663_TEST_MODE_1:
+	case RT5663_TEST_MODE_2:
+	case RT5663_TEST_MODE_3:
+	case RT5663_STO_DRE_1:
+	case RT5663_STO_DRE_2:
+	case RT5663_STO_DRE_3:
+	case RT5663_STO_DRE_4:
+	case RT5663_STO_DRE_5:
+	case RT5663_STO_DRE_6:
+	case RT5663_STO_DRE_7:
+	case RT5663_STO_DRE_8:
+	case RT5663_STO_DRE_9:
+	case RT5663_STO_DRE_10:
+	case RT5663_MIC_DECRO_1:
+	case RT5663_MIC_DECRO_2:
+	case RT5663_MIC_DECRO_3:
+	case RT5663_MIC_DECRO_4:
+	case RT5663_MIC_DECRO_5:
+	case RT5663_MIC_DECRO_6:
+	case RT5663_HP_DECRO_1:
+	case RT5663_HP_DECRO_2:
+	case RT5663_HP_DECRO_3:
+	case RT5663_HP_DECRO_4:
+	case RT5663_HP_DECOUP:
+	case RT5663_HP_IMP_SEN_MAP8:
+	case RT5663_HP_IMP_SEN_MAP9:
+	case RT5663_HP_IMP_SEN_MAP10:
+	case RT5663_HP_IMP_SEN_MAP11:
+	case RT5663_HP_IMP_SEN_1:
+	case RT5663_HP_IMP_SEN_2:
+	case RT5663_HP_IMP_SEN_3:
+	case RT5663_HP_IMP_SEN_4:
+	case RT5663_HP_IMP_SEN_5:
+	case RT5663_HP_IMP_SEN_6:
+	case RT5663_HP_IMP_SEN_7:
+	case RT5663_HP_IMP_SEN_8:
+	case RT5663_HP_IMP_SEN_9:
+	case RT5663_HP_IMP_SEN_10:
+	case RT5663_HP_IMP_SEN_11:
+	case RT5663_HP_IMP_SEN_12:
+	case RT5663_HP_IMP_SEN_13:
+	case RT5663_HP_IMP_SEN_14:
+	case RT5663_HP_IMP_SEN_15:
+	case RT5663_HP_IMP_SEN_16:
+	case RT5663_HP_IMP_SEN_17:
+	case RT5663_HP_IMP_SEN_18:
+	case RT5663_HP_IMP_SEN_19:
+	case RT5663_HP_IMPSEN_DIG5:
+	case RT5663_HP_IMPSEN_MAP1:
+	case RT5663_HP_IMPSEN_MAP2:
+	case RT5663_HP_IMPSEN_MAP3:
+	case RT5663_HP_IMPSEN_MAP4:
+	case RT5663_HP_IMPSEN_MAP5:
+	case RT5663_HP_IMPSEN_MAP7:
+	case RT5663_HP_LOGIC_1:
+	case RT5663_HP_LOGIC_2:
+	case RT5663_HP_CALIB_1:
+	case RT5663_HP_CALIB_1_1:
+	case RT5663_HP_CALIB_2:
+	case RT5663_HP_CALIB_3:
+	case RT5663_HP_CALIB_4:
+	case RT5663_HP_CALIB_5:
+	case RT5663_HP_CALIB_5_1:
+	case RT5663_HP_CALIB_6:
+	case RT5663_HP_CALIB_7:
+	case RT5663_HP_CALIB_9:
+	case RT5663_HP_CALIB_10:
+	case RT5663_HP_CALIB_11:
+	case RT5663_HP_CALIB_ST1:
+	case RT5663_HP_CALIB_ST2:
+	case RT5663_HP_CALIB_ST3:
+	case RT5663_HP_CALIB_ST4:
+	case RT5663_HP_CALIB_ST5:
+	case RT5663_HP_CALIB_ST6:
+	case RT5663_HP_CALIB_ST7:
+	case RT5663_HP_CALIB_ST8:
+	case RT5663_HP_CALIB_ST9:
+	case RT5663_HP_AMP_DET:
+	case RT5663_DUMMY_REG_6:
+	case RT5663_HP_BIAS:
+	case RT5663_CBJ_1:
+	case RT5663_CBJ_2:
+	case RT5663_CBJ_3:
+	case RT5663_DUMMY_1:
+	case RT5663_DUMMY_2:
+	case RT5663_DUMMY_3:
+	case RT5663_ANA_JD:
+	case RT5663_ADC_LCH_LPF1_A1:
+	case RT5663_ADC_RCH_LPF1_A1:
+	case RT5663_ADC_LCH_LPF1_H0:
+	case RT5663_ADC_RCH_LPF1_H0:
+	case RT5663_ADC_LCH_BPF1_A1:
+	case RT5663_ADC_RCH_BPF1_A1:
+	case RT5663_ADC_LCH_BPF1_A2:
+	case RT5663_ADC_RCH_BPF1_A2:
+	case RT5663_ADC_LCH_BPF1_H0:
+	case RT5663_ADC_RCH_BPF1_H0:
+	case RT5663_ADC_LCH_BPF2_A1:
+	case RT5663_ADC_RCH_BPF2_A1:
+	case RT5663_ADC_LCH_BPF2_A2:
+	case RT5663_ADC_RCH_BPF2_A2:
+	case RT5663_ADC_LCH_BPF2_H0:
+	case RT5663_ADC_RCH_BPF2_H0:
+	case RT5663_ADC_LCH_BPF3_A1:
+	case RT5663_ADC_RCH_BPF3_A1:
+	case RT5663_ADC_LCH_BPF3_A2:
+	case RT5663_ADC_RCH_BPF3_A2:
+	case RT5663_ADC_LCH_BPF3_H0:
+	case RT5663_ADC_RCH_BPF3_H0:
+	case RT5663_ADC_LCH_BPF4_A1:
+	case RT5663_ADC_RCH_BPF4_A1:
+	case RT5663_ADC_LCH_BPF4_A2:
+	case RT5663_ADC_RCH_BPF4_A2:
+	case RT5663_ADC_LCH_BPF4_H0:
+	case RT5663_ADC_RCH_BPF4_H0:
+	case RT5663_ADC_LCH_HPF1_A1:
+	case RT5663_ADC_RCH_HPF1_A1:
+	case RT5663_ADC_LCH_HPF1_H0:
+	case RT5663_ADC_RCH_HPF1_H0:
+	case RT5663_ADC_EQ_PRE_VOL_L:
+	case RT5663_ADC_EQ_PRE_VOL_R:
+	case RT5663_ADC_EQ_POST_VOL_L:
+	case RT5663_ADC_EQ_POST_VOL_R:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5668_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5663_RESET:
+	case RT5668_CBJ_TYPE_2:
+	case RT5668_PDM_OUT_CTL:
+	case RT5668_PDM_I2C_DATA_CTL1:
+	case RT5668_PDM_I2C_DATA_CTL4:
+	case RT5668_ALC_BK_GAIN:
+	case RT5663_PLL_2:
+	case RT5663_MICBIAS_1:
+	case RT5663_ADC_EQ_1:
+	case RT5663_INT_ST_1:
+	case RT5668_GPIO_STA:
+	case RT5663_IL_CMD_1:
+	case RT5663_IL_CMD_5:
+	case RT5668_A_JD_CTRL:
+	case RT5663_JD_CTRL2:
+	case RT5663_VENDOR_ID:
+	case RT5663_VENDOR_ID_1:
+	case RT5663_VENDOR_ID_2:
+	case RT5663_STO_DRE_1:
+	case RT5663_STO_DRE_5:
+	case RT5663_STO_DRE_6:
+	case RT5663_STO_DRE_7:
+	case RT5668_MONO_DYNA_6:
+	case RT5668_STO1_SIL_DET:
+	case RT5668_MONOL_SIL_DET:
+	case RT5668_MONOR_SIL_DET:
+	case RT5668_STO2_DAC_SIL:
+	case RT5668_MONO_AMP_CAL_ST1:
+	case RT5668_MONO_AMP_CAL_ST2:
+	case RT5668_MONO_AMP_CAL_ST3:
+	case RT5668_MONO_AMP_CAL_ST4:
+	case RT5663_HP_IMP_SEN_2:
+	case RT5663_HP_IMP_SEN_3:
+	case RT5663_HP_IMP_SEN_4:
+	case RT5663_HP_IMP_SEN_10:
+	case RT5663_HP_CALIB_1:
+	case RT5663_HP_CALIB_10:
+	case RT5663_HP_CALIB_ST1:
+	case RT5663_HP_CALIB_ST4:
+	case RT5663_HP_CALIB_ST5:
+	case RT5663_HP_CALIB_ST6:
+	case RT5663_HP_CALIB_ST7:
+	case RT5663_HP_CALIB_ST8:
+	case RT5663_HP_CALIB_ST9:
+	case RT5668_HP_CALIB_ST10:
+	case RT5668_HP_CALIB_ST11:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5668_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5668_LOUT_CTRL:
+	case RT5668_HP_AMP_2:
+	case RT5668_MONO_OUT:
+	case RT5668_MONO_GAIN:
+	case RT5668_AEC_BST:
+	case RT5668_IN1_IN2:
+	case RT5668_IN3_IN4:
+	case RT5668_INL1_INR1:
+	case RT5668_CBJ_TYPE_2:
+	case RT5668_CBJ_TYPE_3:
+	case RT5668_CBJ_TYPE_4:
+	case RT5668_CBJ_TYPE_5:
+	case RT5668_CBJ_TYPE_8:
+	case RT5668_DAC3_DIG_VOL:
+	case RT5668_DAC3_CTRL:
+	case RT5668_MONO_ADC_DIG_VOL:
+	case RT5668_STO2_ADC_DIG_VOL:
+	case RT5668_MONO_ADC_BST_GAIN:
+	case RT5668_STO2_ADC_BST_GAIN:
+	case RT5668_SIDETONE_CTRL:
+	case RT5668_MONO1_ADC_MIXER:
+	case RT5668_STO2_ADC_MIXER:
+	case RT5668_MONO_DAC_MIXER:
+	case RT5668_DAC2_SRC_CTRL:
+	case RT5668_IF_3_4_DATA_CTL:
+	case RT5668_IF_5_DATA_CTL:
+	case RT5668_PDM_OUT_CTL:
+	case RT5668_PDM_I2C_DATA_CTL1:
+	case RT5668_PDM_I2C_DATA_CTL2:
+	case RT5668_PDM_I2C_DATA_CTL3:
+	case RT5668_PDM_I2C_DATA_CTL4:
+	case RT5668_RECMIX1_NEW:
+	case RT5668_RECMIX1L_0:
+	case RT5668_RECMIX1L:
+	case RT5668_RECMIX1R_0:
+	case RT5668_RECMIX1R:
+	case RT5668_RECMIX2_NEW:
+	case RT5668_RECMIX2_L_2:
+	case RT5668_RECMIX2_R:
+	case RT5668_RECMIX2_R_2:
+	case RT5668_CALIB_REC_LR:
+	case RT5668_ALC_BK_GAIN:
+	case RT5668_MONOMIX_GAIN:
+	case RT5668_MONOMIX_IN_GAIN:
+	case RT5668_OUT_MIXL_GAIN:
+	case RT5668_OUT_LMIX_IN_GAIN:
+	case RT5668_OUT_RMIX_IN_GAIN:
+	case RT5668_OUT_RMIX_IN_GAIN1:
+	case RT5668_LOUT_MIXER_CTRL:
+	case RT5668_PWR_VOL:
+	case RT5668_ADCDAC_RST:
+	case RT5668_I2S34_SDP:
+	case RT5668_I2S5_SDP:
+	case RT5668_TDM_5:
+	case RT5668_TDM_6:
+	case RT5668_TDM_7:
+	case RT5668_TDM_8:
+	case RT5668_ASRC_3:
+	case RT5668_ASRC_6:
+	case RT5668_ASRC_7:
+	case RT5668_PLL_TRK_13:
+	case RT5668_I2S_M_CLK_CTL:
+	case RT5668_FDIV_I2S34_M_CLK:
+	case RT5668_FDIV_I2S34_M_CLK2:
+	case RT5668_FDIV_I2S5_M_CLK:
+	case RT5668_FDIV_I2S5_M_CLK2:
+	case RT5668_IRQ_4:
+	case RT5668_GPIO_3:
+	case RT5668_GPIO_4:
+	case RT5668_GPIO_STA:
+	case RT5668_HP_AMP_DET1:
+	case RT5668_HP_AMP_DET2:
+	case RT5668_HP_AMP_DET3:
+	case RT5668_MID_BD_HP_AMP:
+	case RT5668_LOW_BD_HP_AMP:
+	case RT5668_SOF_VOL_ZC2:
+	case RT5668_ADC_STO2_ADJ1:
+	case RT5668_ADC_STO2_ADJ2:
+	case RT5668_A_JD_CTRL:
+	case RT5668_JD1_TRES_CTRL:
+	case RT5668_JD2_TRES_CTRL:
+	case RT5668_JD_CTRL2:
+	case RT5668_DUM_REG_2:
+	case RT5668_DUM_REG_3:
+	case RT5663_VENDOR_ID:
+	case RT5663_VENDOR_ID_1:
+	case RT5663_VENDOR_ID_2:
+	case RT5668_DACADC_DIG_VOL2:
+	case RT5668_DIG_IN_PIN2:
+	case RT5668_PAD_DRV_CTL1:
+	case RT5668_SOF_RAM_DEPOP:
+	case RT5668_VOL_TEST:
+	case RT5668_TEST_MODE_3:
+	case RT5668_TEST_MODE_4:
+	case RT5663_STO_DRE_9:
+	case RT5668_MONO_DYNA_1:
+	case RT5668_MONO_DYNA_2:
+	case RT5668_MONO_DYNA_3:
+	case RT5668_MONO_DYNA_4:
+	case RT5668_MONO_DYNA_5:
+	case RT5668_MONO_DYNA_6:
+	case RT5668_STO1_SIL_DET:
+	case RT5668_MONOL_SIL_DET:
+	case RT5668_MONOR_SIL_DET:
+	case RT5668_STO2_DAC_SIL:
+	case RT5668_PWR_SAV_CTL1:
+	case RT5668_PWR_SAV_CTL2:
+	case RT5668_PWR_SAV_CTL3:
+	case RT5668_PWR_SAV_CTL4:
+	case RT5668_PWR_SAV_CTL5:
+	case RT5668_PWR_SAV_CTL6:
+	case RT5668_MONO_AMP_CAL1:
+	case RT5668_MONO_AMP_CAL2:
+	case RT5668_MONO_AMP_CAL3:
+	case RT5668_MONO_AMP_CAL4:
+	case RT5668_MONO_AMP_CAL5:
+	case RT5668_MONO_AMP_CAL6:
+	case RT5668_MONO_AMP_CAL7:
+	case RT5668_MONO_AMP_CAL_ST1:
+	case RT5668_MONO_AMP_CAL_ST2:
+	case RT5668_MONO_AMP_CAL_ST3:
+	case RT5668_MONO_AMP_CAL_ST4:
+	case RT5668_MONO_AMP_CAL_ST5:
+	case RT5668_HP_IMP_SEN_13:
+	case RT5668_HP_IMP_SEN_14:
+	case RT5668_HP_IMP_SEN_6:
+	case RT5668_HP_IMP_SEN_7:
+	case RT5668_HP_IMP_SEN_8:
+	case RT5668_HP_IMP_SEN_9:
+	case RT5668_HP_IMP_SEN_10:
+	case RT5668_HP_LOGIC_3:
+	case RT5668_HP_CALIB_ST10:
+	case RT5668_HP_CALIB_ST11:
+	case RT5668_PRO_REG_TBL_4:
+	case RT5668_PRO_REG_TBL_5:
+	case RT5668_PRO_REG_TBL_6:
+	case RT5668_PRO_REG_TBL_7:
+	case RT5668_PRO_REG_TBL_8:
+	case RT5668_PRO_REG_TBL_9:
+	case RT5668_SAR_ADC_INL_1:
+	case RT5668_SAR_ADC_INL_2:
+	case RT5668_SAR_ADC_INL_3:
+	case RT5668_SAR_ADC_INL_4:
+	case RT5668_SAR_ADC_INL_5:
+	case RT5668_SAR_ADC_INL_6:
+	case RT5668_SAR_ADC_INL_7:
+	case RT5668_SAR_ADC_INL_8:
+	case RT5668_SAR_ADC_INL_9:
+	case RT5668_SAR_ADC_INL_10:
+	case RT5668_SAR_ADC_INL_11:
+	case RT5668_SAR_ADC_INL_12:
+	case RT5668_DRC_CTRL_1:
+	case RT5668_DRC1_CTRL_2:
+	case RT5668_DRC1_CTRL_3:
+	case RT5668_DRC1_CTRL_4:
+	case RT5668_DRC1_CTRL_5:
+	case RT5668_DRC1_CTRL_6:
+	case RT5668_DRC1_HD_CTRL_1:
+	case RT5668_DRC1_HD_CTRL_2:
+	case RT5668_DRC1_PRI_REG_1:
+	case RT5668_DRC1_PRI_REG_2:
+	case RT5668_DRC1_PRI_REG_3:
+	case RT5668_DRC1_PRI_REG_4:
+	case RT5668_DRC1_PRI_REG_5:
+	case RT5668_DRC1_PRI_REG_6:
+	case RT5668_DRC1_PRI_REG_7:
+	case RT5668_DRC1_PRI_REG_8:
+	case RT5668_ALC_PGA_CTL_1:
+	case RT5668_ALC_PGA_CTL_2:
+	case RT5668_ALC_PGA_CTL_3:
+	case RT5668_ALC_PGA_CTL_4:
+	case RT5668_ALC_PGA_CTL_5:
+	case RT5668_ALC_PGA_CTL_6:
+	case RT5668_ALC_PGA_CTL_7:
+	case RT5668_ALC_PGA_CTL_8:
+	case RT5668_ALC_PGA_REG_1:
+	case RT5668_ALC_PGA_REG_2:
+	case RT5668_ALC_PGA_REG_3:
+	case RT5668_ADC_EQ_RECOV_1:
+	case RT5668_ADC_EQ_RECOV_2:
+	case RT5668_ADC_EQ_RECOV_3:
+	case RT5668_ADC_EQ_RECOV_4:
+	case RT5668_ADC_EQ_RECOV_5:
+	case RT5668_ADC_EQ_RECOV_6:
+	case RT5668_ADC_EQ_RECOV_7:
+	case RT5668_ADC_EQ_RECOV_8:
+	case RT5668_ADC_EQ_RECOV_9:
+	case RT5668_ADC_EQ_RECOV_10:
+	case RT5668_ADC_EQ_RECOV_11:
+	case RT5668_ADC_EQ_RECOV_12:
+	case RT5668_ADC_EQ_RECOV_13:
+	case RT5668_VID_HIDDEN:
+	case RT5668_VID_CUSTOMER:
+	case RT5668_SCAN_MODE:
+	case RT5668_I2C_BYPA:
+		return true;
+	case RT5663_TDM_1:
+	case RT5663_DEPOP_3:
+	case RT5663_ASRC_11_2:
+	case RT5663_INT_ST_2:
+	case RT5663_GPIO_STA:
+	case RT5663_SIN_GEN_1:
+	case RT5663_SIN_GEN_2:
+	case RT5663_SIN_GEN_3:
+	case RT5663_IL_CMD_PWRSAV1:
+	case RT5663_IL_CMD_PWRSAV2:
+	case RT5663_EM_JACK_TYPE_1:
+	case RT5663_EM_JACK_TYPE_2:
+	case RT5663_EM_JACK_TYPE_3:
+	case RT5663_EM_JACK_TYPE_4:
+	case RT5663_FAST_OFF_MICBIAS:
+	case RT5663_ANA_BIAS_CUR_1:
+	case RT5663_ANA_BIAS_CUR_2:
+	case RT5663_BIAS_CUR_9:
+	case RT5663_DUMMY_REG_4:
+	case RT5663_VREF_RECMIX:
+	case RT5663_CHARGE_PUMP_1_2:
+	case RT5663_CHARGE_PUMP_1_3:
+	case RT5663_CHARGE_PUMP_2:
+	case RT5663_CHOP_DAC_R:
+	case RT5663_DUMMY_CTL_DACLR:
+	case RT5663_DUMMY_REG_5:
+	case RT5663_SOFT_RAMP:
+	case RT5663_TEST_MODE_1:
+	case RT5663_STO_DRE_10:
+	case RT5663_MIC_DECRO_1:
+	case RT5663_MIC_DECRO_2:
+	case RT5663_MIC_DECRO_3:
+	case RT5663_MIC_DECRO_4:
+	case RT5663_MIC_DECRO_5:
+	case RT5663_MIC_DECRO_6:
+	case RT5663_HP_DECRO_1:
+	case RT5663_HP_DECRO_2:
+	case RT5663_HP_DECRO_3:
+	case RT5663_HP_DECRO_4:
+	case RT5663_HP_DECOUP:
+	case RT5663_HP_IMPSEN_MAP4:
+	case RT5663_HP_IMPSEN_MAP5:
+	case RT5663_HP_IMPSEN_MAP7:
+	case RT5663_HP_CALIB_1:
+	case RT5663_CBJ_1:
+	case RT5663_CBJ_2:
+	case RT5663_CBJ_3:
+		return false;
+	default:
+		return rt5663_readable_register(dev, reg);
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(rt5663_hp_vol_tlv, -2400, 150, 0);
+static const DECLARE_TLV_DB_SCALE(rt5668_hp_vol_tlv, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static const DECLARE_TLV_DB_RANGE(in_bst_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+	3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+	6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+	7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
+
+/* Interface data select */
+static const char * const rt5663_if1_adc_data_select[] = {
+	"L/R", "R/L", "L/L", "R/R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5663_if1_adc_enum, RT5663_TDM_2,
+	RT5663_DATA_SWAP_ADCDAT1_SHIFT, rt5663_if1_adc_data_select);
+
+static void rt5663_enable_push_button_irq(struct snd_soc_codec *codec,
+	bool enable)
+{
+	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+
+	if (enable) {
+		snd_soc_update_bits(codec, RT5663_IL_CMD_6,
+			RT5668_EN_4BTN_INL_MASK, RT5668_EN_4BTN_INL_EN);
+		/* reset in-line command */
+		snd_soc_update_bits(codec, RT5663_IL_CMD_6,
+			RT5668_RESET_4BTN_INL_MASK,
+			RT5668_RESET_4BTN_INL_RESET);
+		snd_soc_update_bits(codec, RT5663_IL_CMD_6,
+			RT5668_RESET_4BTN_INL_MASK,
+			RT5668_RESET_4BTN_INL_NOR);
+		switch (rt5663->codec_type) {
+		case CODEC_TYPE_RT5668:
+			snd_soc_update_bits(codec, RT5663_IRQ_3,
+				RT5668_EN_IRQ_INLINE_MASK,
+				RT5668_EN_IRQ_INLINE_NOR);
+			break;
+		case CODEC_TYPE_RT5663:
+			snd_soc_update_bits(codec, RT5663_IRQ_2,
+				RT5663_EN_IRQ_INLINE_MASK,
+				RT5663_EN_IRQ_INLINE_NOR);
+			break;
+		default:
+			dev_err(codec->dev, "Unknown CODEC_TYPE\n");
+		}
+	} else {
+		switch (rt5663->codec_type) {
+		case CODEC_TYPE_RT5668:
+			snd_soc_update_bits(codec, RT5663_IRQ_3,
+				RT5668_EN_IRQ_INLINE_MASK,
+				RT5668_EN_IRQ_INLINE_BYP);
+			break;
+		case CODEC_TYPE_RT5663:
+			snd_soc_update_bits(codec, RT5663_IRQ_2,
+				RT5663_EN_IRQ_INLINE_MASK,
+				RT5663_EN_IRQ_INLINE_BYP);
+			break;
+		default:
+			dev_err(codec->dev, "Unknown CODEC_TYPE\n");
+		}
+		snd_soc_update_bits(codec, RT5663_IL_CMD_6,
+			RT5668_EN_4BTN_INL_MASK, RT5668_EN_4BTN_INL_DIS);
+		/* reset in-line command */
+		snd_soc_update_bits(codec, RT5663_IL_CMD_6,
+			RT5668_RESET_4BTN_INL_MASK,
+			RT5668_RESET_4BTN_INL_RESET);
+		snd_soc_update_bits(codec, RT5663_IL_CMD_6,
+			RT5668_RESET_4BTN_INL_MASK,
+			RT5668_RESET_4BTN_INL_NOR);
+	}
+}
+
+/**
+ * rt5668_jack_detect - Detect headset.
+ * @codec: SoC audio codec device.
+ * @jack_insert: Jack insert or not.
+ *
+ * Detect whether is headset or not when jack inserted.
+ *
+ * Returns detect status.
+ */
+
+static int rt5668_jack_detect(struct snd_soc_codec *codec, int jack_insert)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct rt5663_priv *rt5668 = snd_soc_codec_get_drvdata(codec);
+	int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30};
+
+	dev_dbg(codec->dev, "%s jack_insert:%d\n", __func__, jack_insert);
+	if (jack_insert) {
+		snd_soc_write(codec, RT5668_CBJ_TYPE_2, 0x8040);
+		snd_soc_write(codec, RT5668_CBJ_TYPE_3, 0x1484);
+
+		snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
+		snd_soc_dapm_force_enable_pin(dapm, "MICBIAS2");
+		snd_soc_dapm_force_enable_pin(dapm, "Mic Det Power");
+		snd_soc_dapm_force_enable_pin(dapm, "CBJ Power");
+		snd_soc_dapm_sync(dapm);
+		snd_soc_update_bits(codec, RT5663_RC_CLK,
+			RT5668_DIG_1M_CLK_MASK, RT5668_DIG_1M_CLK_EN);
+		snd_soc_update_bits(codec, RT5663_RECMIX, 0x8, 0x8);
+
+		while (i < 5) {
+			msleep(sleep_time[i]);
+			val = snd_soc_read(codec, RT5668_CBJ_TYPE_2) & 0x0003;
+			if (val == 0x1 || val == 0x2 || val == 0x3)
+				break;
+			dev_dbg(codec->dev, "%s: MX-0011 val=%x sleep %d\n",
+				__func__, val, sleep_time[i]);
+			i++;
+		}
+		dev_dbg(codec->dev, "%s val = %d\n", __func__, val);
+		switch (val) {
+		case 1:
+		case 2:
+			rt5668->jack_type = SND_JACK_HEADSET;
+			rt5663_enable_push_button_irq(codec, true);
+			break;
+		default:
+			snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
+			snd_soc_dapm_disable_pin(dapm, "MICBIAS2");
+			snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+			snd_soc_dapm_disable_pin(dapm, "CBJ Power");
+			snd_soc_dapm_sync(dapm);
+			rt5668->jack_type = SND_JACK_HEADPHONE;
+			break;
+		}
+	} else {
+		snd_soc_update_bits(codec, RT5663_RECMIX, 0x8, 0x0);
+
+		if (rt5668->jack_type == SND_JACK_HEADSET) {
+			rt5663_enable_push_button_irq(codec, false);
+			snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
+			snd_soc_dapm_disable_pin(dapm, "MICBIAS2");
+			snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+			snd_soc_dapm_disable_pin(dapm, "CBJ Power");
+			snd_soc_dapm_sync(dapm);
+		}
+		rt5668->jack_type = 0;
+	}
+
+	dev_dbg(codec->dev, "jack_type = %d\n", rt5668->jack_type);
+	return rt5668->jack_type;
+}
+
+/**
+ * rt5663_jack_detect - Detect headset.
+ * @codec: SoC audio codec device.
+ * @jack_insert: Jack insert or not.
+ *
+ * Detect whether is headset or not when jack inserted.
+ *
+ * Returns detect status.
+ */
+static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert)
+{
+	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30};
+
+	dev_dbg(codec->dev, "%s jack_insert:%d\n", __func__, jack_insert);
+
+	if (jack_insert) {
+		snd_soc_update_bits(codec, RT5663_DIG_MISC,
+			RT5668_DIG_GATE_CTRL_MASK, RT5668_DIG_GATE_CTRL_EN);
+		snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1,
+			RT5663_SI_HP_MASK | RT5668_OSW_HP_L_MASK |
+			RT5668_OSW_HP_R_MASK, RT5663_SI_HP_EN |
+			RT5668_OSW_HP_L_DIS | RT5668_OSW_HP_R_DIS);
+		snd_soc_update_bits(codec, RT5663_DUMMY_1,
+			RT5663_EMB_CLK_MASK | RT5663_HPA_CPL_BIAS_MASK |
+			RT5663_HPA_CPR_BIAS_MASK, RT5663_EMB_CLK_EN |
+			RT5663_HPA_CPL_BIAS_1 | RT5663_HPA_CPR_BIAS_1);
+		snd_soc_update_bits(codec, RT5663_CBJ_1,
+			RT5663_INBUF_CBJ_BST1_MASK | RT5663_CBJ_SENSE_BST1_MASK,
+			RT5663_INBUF_CBJ_BST1_ON | RT5663_CBJ_SENSE_BST1_L);
+		snd_soc_update_bits(codec, RT5663_IL_CMD_2,
+			RT5663_PWR_MIC_DET_MASK, RT5663_PWR_MIC_DET_ON);
+		/* BST1 power on for JD */
+		snd_soc_update_bits(codec, RT5663_PWR_ANLG_2,
+			RT5668_PWR_BST1_MASK, RT5668_PWR_BST1_ON);
+		snd_soc_update_bits(codec, RT5663_EM_JACK_TYPE_1,
+			RT5663_CBJ_DET_MASK | RT5663_EXT_JD_MASK |
+			RT5663_POL_EXT_JD_MASK, RT5663_CBJ_DET_EN |
+			RT5663_EXT_JD_EN | RT5663_POL_EXT_JD_EN);
+		snd_soc_update_bits(codec, RT5663_PWR_ANLG_1,
+			RT5668_PWR_MB_MASK | RT5668_LDO1_DVO_MASK |
+			RT5668_AMP_HP_MASK, RT5668_PWR_MB |
+			RT5668_LDO1_DVO_0_9V | RT5668_AMP_HP_3X);
+		snd_soc_update_bits(codec, RT5663_AUTO_1MRC_CLK,
+			RT5668_IRQ_POW_SAV_MASK, RT5668_IRQ_POW_SAV_EN);
+		snd_soc_update_bits(codec, RT5663_IRQ_1,
+			RT5663_EN_IRQ_JD1_MASK, RT5663_EN_IRQ_JD1_EN);
+		while (i < 5) {
+			msleep(sleep_time[i]);
+			val = snd_soc_read(codec, RT5663_EM_JACK_TYPE_2) &
+				0x0003;
+			i++;
+			if (val == 0x1 || val == 0x2 || val == 0x3)
+				break;
+			dev_dbg(codec->dev, "%s: MX-00e7 val=%x sleep %d\n",
+				__func__, val, sleep_time[i]);
+		}
+		dev_dbg(codec->dev, "%s val = %d\n", __func__, val);
+		switch (val) {
+		case 1:
+		case 2:
+			rt5663->jack_type = SND_JACK_HEADSET;
+			rt5663_enable_push_button_irq(codec, true);
+			break;
+		default:
+			rt5663->jack_type = SND_JACK_HEADPHONE;
+			break;
+		}
+	} else {
+		if (rt5663->jack_type == SND_JACK_HEADSET)
+			rt5663_enable_push_button_irq(codec, false);
+		rt5663->jack_type = 0;
+	}
+
+	dev_dbg(codec->dev, "jack_type = %d\n", rt5663->jack_type);
+	return rt5663->jack_type;
+}
+
+static int rt5663_button_detect(struct snd_soc_codec *codec)
+{
+	int btn_type, val;
+
+	val = snd_soc_read(codec, RT5663_IL_CMD_5);
+	dev_dbg(codec->dev, "%s: val=0x%x\n", __func__, val);
+	btn_type = val & 0xfff0;
+	snd_soc_write(codec, RT5663_IL_CMD_5, val);
+
+	return btn_type;
+}
+
+static irqreturn_t rt5663_irq(int irq, void *data)
+{
+	struct rt5663_priv *rt5663 = data;
+
+	dev_dbg(rt5663->codec->dev, "%s IRQ queue work\n", __func__);
+
+	queue_delayed_work(system_wq, &rt5663->jack_detect_work,
+		msecs_to_jiffies(250));
+
+	return IRQ_HANDLED;
+}
+
+int rt5663_set_jack_detect(struct snd_soc_codec *codec,
+	struct snd_soc_jack *hs_jack)
+{
+	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+
+	rt5663->hs_jack = hs_jack;
+
+	rt5663_irq(0, rt5663);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5663_set_jack_detect);
+
+static bool rt5663_check_jd_status(struct snd_soc_codec *codec)
+{
+	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	int val = snd_soc_read(codec, RT5663_INT_ST_1);
+
+	dev_dbg(codec->dev, "%s val=%x\n", __func__, val);
+
+	/* JD1 */
+	switch (rt5663->codec_type) {
+	case CODEC_TYPE_RT5668:
+		return !(val & 0x2000);
+	case CODEC_TYPE_RT5663:
+		return !(val & 0x1000);
+	default:
+		dev_err(codec->dev, "Unknown CODEC_TYPE\n");
+	}
+
+	return false;
+}
+
+static void rt5663_jack_detect_work(struct work_struct *work)
+{
+	struct rt5663_priv *rt5663 =
+		container_of(work, struct rt5663_priv, jack_detect_work.work);
+	struct snd_soc_codec *codec = rt5663->codec;
+	int btn_type, report = 0;
+
+	if (!codec)
+		return;
+
+	if (rt5663_check_jd_status(codec)) {
+		/* jack in */
+		if (rt5663->jack_type == 0) {
+			/* jack was out, report jack type */
+			switch (rt5663->codec_type) {
+			case CODEC_TYPE_RT5668:
+				report = rt5668_jack_detect(rt5663->codec, 1);
+				break;
+			case CODEC_TYPE_RT5663:
+				report = rt5663_jack_detect(rt5663->codec, 1);
+				break;
+			default:
+				dev_err(codec->dev, "Unknown CODEC_TYPE\n");
+			}
+		} else {
+			/* jack is already in, report button event */
+			report = SND_JACK_HEADSET;
+			btn_type = rt5663_button_detect(rt5663->codec);
+			/**
+			 * rt5663 can report three kinds of button behavior,
+			 * one click, double click and hold. However,
+			 * currently we will report button pressed/released
+			 * event. So all the three button behaviors are
+			 * treated as button pressed.
+			 */
+			switch (btn_type) {
+			case 0x8000:
+			case 0x4000:
+			case 0x2000:
+				report |= SND_JACK_BTN_0;
+				break;
+			case 0x1000:
+			case 0x0800:
+			case 0x0400:
+				report |= SND_JACK_BTN_1;
+				break;
+			case 0x0200:
+			case 0x0100:
+			case 0x0080:
+				report |= SND_JACK_BTN_2;
+				break;
+			case 0x0040:
+			case 0x0020:
+			case 0x0010:
+				report |= SND_JACK_BTN_3;
+				break;
+			case 0x0000: /* unpressed */
+				break;
+			default:
+				btn_type = 0;
+				dev_err(rt5663->codec->dev,
+					"Unexpected button code 0x%04x\n",
+					btn_type);
+				break;
+			}
+			/* button release or spurious interrput*/
+			if (btn_type == 0)
+				report =  rt5663->jack_type;
+		}
+	} else {
+		/* jack out */
+		switch (rt5663->codec_type) {
+		case CODEC_TYPE_RT5668:
+			report = rt5668_jack_detect(rt5663->codec, 0);
+			break;
+		case CODEC_TYPE_RT5663:
+			report = rt5663_jack_detect(rt5663->codec, 0);
+			break;
+		default:
+			dev_err(codec->dev, "Unknown CODEC_TYPE\n");
+		}
+	}
+	dev_dbg(codec->dev, "%s jack report: 0x%04x\n", __func__, report);
+	snd_soc_jack_report(rt5663->hs_jack, report, SND_JACK_HEADSET |
+			    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+			    SND_JACK_BTN_2 | SND_JACK_BTN_3);
+}
+
+static const struct snd_kcontrol_new rt5663_snd_controls[] = {
+	/* DAC Digital Volume */
+	SOC_DOUBLE_TLV("DAC Playback Volume", RT5663_STO1_DAC_DIG_VOL,
+		RT5668_DAC_L1_VOL_SHIFT + 1, RT5668_DAC_R1_VOL_SHIFT + 1,
+		87, 0, dac_vol_tlv),
+	/* ADC Digital Volume Control */
+	SOC_DOUBLE("ADC Capture Switch", RT5663_STO1_ADC_DIG_VOL,
+		RT5668_ADC_L_MUTE_SHIFT, RT5668_ADC_R_MUTE_SHIFT, 1, 1),
+	SOC_DOUBLE_TLV("ADC Capture Volume", RT5663_STO1_ADC_DIG_VOL,
+		RT5668_ADC_L_VOL_SHIFT + 1, RT5668_ADC_R_VOL_SHIFT + 1,
+		63, 0, adc_vol_tlv),
+};
+
+static const struct snd_kcontrol_new rt5668_specific_controls[] = {
+	/* Headphone Output Volume */
+	SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5663_HP_LCH_DRE,
+		RT5663_HP_RCH_DRE, RT5668_GAIN_HP_SHIFT, 15, 1,
+		rt5668_hp_vol_tlv),
+	/* Mic Boost Volume */
+	SOC_SINGLE_TLV("IN1 Capture Volume", RT5668_AEC_BST,
+		RT5668_GAIN_CBJ_SHIFT, 8, 0, in_bst_tlv),
+};
+
+static const struct snd_kcontrol_new rt5663_specific_controls[] = {
+	/* Headphone Output Volume */
+	SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5663_STO_DRE_9,
+		RT5663_STO_DRE_10, RT5663_DRE_GAIN_HP_SHIFT, 23, 1,
+		rt5663_hp_vol_tlv),
+	/* Mic Boost Volume*/
+	SOC_SINGLE_TLV("IN1 Capture Volume", RT5663_CBJ_2,
+		RT5663_GAIN_BST1_SHIFT, 8, 0, in_bst_tlv),
+	/* Data Swap for Slot0/1 in ADCDAT1 */
+	SOC_ENUM("IF1 ADC Data Swap", rt5663_if1_adc_enum),
+};
+
+static int rt5663_is_sys_clk_from_pll(struct snd_soc_dapm_widget *w,
+	struct snd_soc_dapm_widget *sink)
+{
+	unsigned int val;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	val = snd_soc_read(codec, RT5663_GLB_CLK);
+	val &= RT5663_SCLK_SRC_MASK;
+	if (val == RT5663_SCLK_SRC_PLL1)
+		return 1;
+	else
+		return 0;
+}
+
+static int rt5663_is_using_asrc(struct snd_soc_dapm_widget *w,
+	struct snd_soc_dapm_widget *sink)
+{
+	unsigned int reg, shift, val;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+
+	if (rt5663->codec_type == CODEC_TYPE_RT5668) {
+		switch (w->shift) {
+		case RT5668_ADC_STO1_ASRC_SHIFT:
+			reg = RT5668_ASRC_3;
+			shift = RT5668_AD_STO1_TRACK_SHIFT;
+			break;
+		case RT5668_DAC_STO1_ASRC_SHIFT:
+			reg = RT5663_ASRC_2;
+			shift = RT5668_DA_STO1_TRACK_SHIFT;
+			break;
+		default:
+			return 0;
+		}
+	} else {
+		switch (w->shift) {
+		case RT5663_ADC_STO1_ASRC_SHIFT:
+			reg = RT5663_ASRC_2;
+			shift = RT5663_AD_STO1_TRACK_SHIFT;
+			break;
+		case RT5663_DAC_STO1_ASRC_SHIFT:
+			reg = RT5663_ASRC_2;
+			shift = RT5663_DA_STO1_TRACK_SHIFT;
+			break;
+		default:
+			return 0;
+		}
+	}
+
+	val = (snd_soc_read(codec, reg) >> shift) & 0x7;
+
+	if (val)
+		return 1;
+
+	return 0;
+}
+
+static int rt5663_i2s_use_asrc(struct snd_soc_dapm_widget *source,
+	struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	int da_asrc_en, ad_asrc_en;
+
+	da_asrc_en = (snd_soc_read(codec, RT5663_ASRC_2) &
+		RT5663_DA_STO1_TRACK_MASK) ? 1 : 0;
+	switch (rt5663->codec_type) {
+	case CODEC_TYPE_RT5668:
+		ad_asrc_en = (snd_soc_read(codec, RT5668_ASRC_3) &
+			RT5668_AD_STO1_TRACK_MASK) ? 1 : 0;
+		break;
+	case CODEC_TYPE_RT5663:
+		ad_asrc_en = (snd_soc_read(codec, RT5663_ASRC_2) &
+			RT5663_AD_STO1_TRACK_MASK) ? 1 : 0;
+		break;
+	default:
+		dev_err(codec->dev, "Unknown CODEC_TYPE\n");
+		return 1;
+	}
+
+	if (da_asrc_en || ad_asrc_en)
+		if (rt5663->sysclk > rt5663->lrck * 384)
+			return 1;
+
+	dev_err(codec->dev, "sysclk < 384 x fs, disable i2s asrc\n");
+
+	return 0;
+}
+
+/**
+ * rt5663_sel_asrc_clk_src - select ASRC clock source for a set of filters
+ * @codec: SoC audio codec device.
+ * @filter_mask: mask of filters.
+ * @clk_src: clock source
+ *
+ * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5668 can
+ * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
+ * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
+ * ASRC function will track i2s clock and generate a corresponding system clock
+ * for codec. This function provides an API to select the clock source for a
+ * set of filters specified by the mask. And the codec driver will turn on ASRC
+ * for these filters if ASRC is selected as their clock source.
+ */
+int rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec,
+		unsigned int filter_mask, unsigned int clk_src)
+{
+	struct rt5663_priv *rt5668 = snd_soc_codec_get_drvdata(codec);
+	unsigned int asrc2_mask = 0;
+	unsigned int asrc2_value = 0;
+	unsigned int asrc3_mask = 0;
+	unsigned int asrc3_value = 0;
+
+	switch (clk_src) {
+	case RT5663_CLK_SEL_SYS:
+	case RT5663_CLK_SEL_I2S1_ASRC:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (filter_mask & RT5663_DA_STEREO_FILTER) {
+		asrc2_mask |= RT5668_DA_STO1_TRACK_MASK;
+		asrc2_value |= clk_src << RT5668_DA_STO1_TRACK_SHIFT;
+	}
+
+	if (filter_mask & RT5663_AD_STEREO_FILTER) {
+		switch (rt5668->codec_type) {
+		case CODEC_TYPE_RT5668:
+			asrc3_mask |= RT5668_AD_STO1_TRACK_MASK;
+			asrc3_value |= clk_src << RT5668_AD_STO1_TRACK_SHIFT;
+			break;
+		case CODEC_TYPE_RT5663:
+			asrc2_mask |= RT5663_AD_STO1_TRACK_MASK;
+			asrc2_value |= clk_src << RT5663_AD_STO1_TRACK_SHIFT;
+			break;
+		default:
+			dev_err(codec->dev, "Unknown CODEC_TYPE\n");
+		}
+	}
+
+	if (asrc2_mask)
+		snd_soc_update_bits(codec, RT5663_ASRC_2, asrc2_mask,
+			asrc2_value);
+
+	if (asrc3_mask)
+		snd_soc_update_bits(codec, RT5668_ASRC_3, asrc3_mask,
+			asrc3_value);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5663_sel_asrc_clk_src);
+
+/* Analog Mixer */
+static const struct snd_kcontrol_new rt5668_recmix1l[] = {
+	SOC_DAPM_SINGLE("BST2 Switch", RT5668_RECMIX1L,
+		RT5668_RECMIX1L_BST2_SHIFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 CBJ Switch", RT5668_RECMIX1L,
+		RT5668_RECMIX1L_BST1_CBJ_SHIFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5668_recmix1r[] = {
+	SOC_DAPM_SINGLE("BST2 Switch", RT5668_RECMIX1R,
+		RT5668_RECMIX1R_BST2_SHIFT, 1, 1),
+};
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5663_sto1_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5663_STO1_ADC_MIXER,
+			RT5668_M_STO1_ADC_L1_SHIFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5663_STO1_ADC_MIXER,
+			RT5668_M_STO1_ADC_L2_SHIFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5668_sto1_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5663_STO1_ADC_MIXER,
+			RT5668_M_STO1_ADC_R1_SHIFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5663_STO1_ADC_MIXER,
+			RT5668_M_STO1_ADC_R2_SHIFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5663_adda_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC L Switch", RT5663_AD_DA_MIXER,
+			RT5668_M_ADCMIX_L_SHIFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L Switch", RT5663_AD_DA_MIXER,
+			RT5668_M_DAC1_L_SHIFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5663_adda_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC R Switch", RT5663_AD_DA_MIXER,
+			RT5668_M_ADCMIX_R_SHIFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R Switch", RT5663_AD_DA_MIXER,
+			RT5668_M_DAC1_R_SHIFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5663_sto1_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L Switch", RT5663_STO_DAC_MIXER,
+			RT5668_M_DAC_L1_STO_L_SHIFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER,
+			RT5668_M_DAC_R1_STO_L_SHIFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5663_sto1_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC L Switch", RT5663_STO_DAC_MIXER,
+			RT5668_M_DAC_L1_STO_R_SHIFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER,
+			RT5668_M_DAC_R1_STO_R_SHIFT, 1, 1),
+};
+
+/* Out Switch */
+static const struct snd_kcontrol_new rt5668_hpo_switch =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5668_HP_AMP_2,
+		RT5668_EN_DAC_HPO_SHIFT, 1, 0);
+
+/* Stereo ADC source */
+static const char * const rt5668_sto1_adc_src[] = {
+	"ADC L", "ADC R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5668_sto1_adcl_enum, RT5663_STO1_ADC_MIXER,
+	RT5668_STO1_ADC_L_SRC_SHIFT, rt5668_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5668_sto1_adcl_mux =
+	SOC_DAPM_ENUM("STO1 ADC L Mux", rt5668_sto1_adcl_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5668_sto1_adcr_enum, RT5663_STO1_ADC_MIXER,
+	RT5668_STO1_ADC_R_SRC_SHIFT, rt5668_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5668_sto1_adcr_mux =
+	SOC_DAPM_ENUM("STO1 ADC R Mux", rt5668_sto1_adcr_enum);
+
+/* RT5663: Analog DACL1 input source */
+static const char * const rt5663_alg_dacl_src[] = {
+	"DAC L", "STO DAC MIXL"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5663_alg_dacl_enum, RT5663_BYPASS_STO_DAC,
+	RT5663_DACL1_SRC_SHIFT, rt5663_alg_dacl_src);
+
+static const struct snd_kcontrol_new rt5663_alg_dacl_mux =
+	SOC_DAPM_ENUM("DAC L Mux", rt5663_alg_dacl_enum);
+
+/* RT5663: Analog DACR1 input source */
+static const char * const rt5663_alg_dacr_src[] = {
+	"DAC R", "STO DAC MIXR"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5663_alg_dacr_enum, RT5663_BYPASS_STO_DAC,
+	RT5663_DACR1_SRC_SHIFT, rt5663_alg_dacr_src);
+
+static const struct snd_kcontrol_new rt5663_alg_dacr_mux =
+	SOC_DAPM_ENUM("DAC R Mux", rt5663_alg_dacr_enum);
+
+static int rt5663_hp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (rt5663->codec_type == CODEC_TYPE_RT5668) {
+			snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1,
+				RT5668_SEL_PM_HP_SHIFT, RT5668_SEL_PM_HP_HIGH);
+			snd_soc_update_bits(codec, RT5663_HP_LOGIC_2,
+				RT5668_HP_SIG_SRC1_MASK,
+				RT5668_HP_SIG_SRC1_SILENCE);
+		} else {
+			snd_soc_write(codec, RT5663_DEPOP_2, 0x3003);
+			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x000b,
+				0x000b);
+			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030,
+				0x0030);
+			snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1,
+				RT5668_OVCD_HP_MASK, RT5668_OVCD_HP_DIS);
+			snd_soc_write(codec, RT5663_HP_CHARGE_PUMP_2, 0x1371);
+			snd_soc_write(codec, RT5663_HP_BIAS, 0xabba);
+			snd_soc_write(codec, RT5663_CHARGE_PUMP_1, 0x2224);
+			snd_soc_write(codec, RT5663_ANA_BIAS_CUR_1, 0x7766);
+			snd_soc_write(codec, RT5663_HP_BIAS, 0xafaa);
+			snd_soc_write(codec, RT5663_CHARGE_PUMP_2, 0x7777);
+			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000,
+				0x3000);
+		}
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		if (rt5663->codec_type == CODEC_TYPE_RT5668) {
+			snd_soc_update_bits(codec, RT5663_HP_LOGIC_2,
+				RT5668_HP_SIG_SRC1_MASK,
+				RT5668_HP_SIG_SRC1_REG);
+		} else {
+			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000, 0x0);
+			snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1,
+				RT5668_OVCD_HP_MASK, RT5668_OVCD_HP_EN);
+			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, 0x0);
+			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x000b,
+				0x000b);
+		}
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5668_bst2_power(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec, RT5663_PWR_ANLG_2,
+			RT5668_PWR_BST2_MASK | RT5668_PWR_BST2_OP_MASK,
+			RT5668_PWR_BST2 | RT5668_PWR_BST2_OP);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, RT5663_PWR_ANLG_2,
+			RT5668_PWR_BST2_MASK | RT5668_PWR_BST2_OP_MASK, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5663_pre_div_power(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_write(codec, RT5663_PRE_DIV_GATING_1, 0xff00);
+		snd_soc_write(codec, RT5663_PRE_DIV_GATING_2, 0xfffc);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_write(codec, RT5663_PRE_DIV_GATING_1, 0x0000);
+		snd_soc_write(codec, RT5663_PRE_DIV_GATING_2, 0x0000);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("PLL", RT5663_PWR_ANLG_3, RT5668_PWR_PLL_SHIFT, 0,
+		NULL, 0),
+
+	/* micbias */
+	SND_SOC_DAPM_MICBIAS("MICBIAS1", RT5663_PWR_ANLG_2,
+		RT5668_PWR_MB1_SHIFT, 0),
+	SND_SOC_DAPM_MICBIAS("MICBIAS2", RT5663_PWR_ANLG_2,
+		RT5668_PWR_MB2_SHIFT, 0),
+
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("IN1P"),
+	SND_SOC_DAPM_INPUT("IN1N"),
+
+	/* REC Mixer Power */
+	SND_SOC_DAPM_SUPPLY("RECMIX1L Power", RT5663_PWR_ANLG_2,
+		RT5668_PWR_RECMIX1_SHIFT, 0, NULL, 0),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_SUPPLY("ADC L Power", RT5663_PWR_DIG_1,
+		RT5668_PWR_ADC_L1_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC Clock", RT5663_CHOP_ADC,
+		RT5668_CKGEN_ADCC_SHIFT, 0, NULL, 0),
+
+	/* ADC Mixer */
+	SND_SOC_DAPM_MIXER("STO1 ADC MIXL", SND_SOC_NOPM,
+		0, 0, rt5663_sto1_adc_l_mix,
+		ARRAY_SIZE(rt5663_sto1_adc_l_mix)),
+
+	/* ADC Filter Power */
+	SND_SOC_DAPM_SUPPLY("STO1 ADC Filter", RT5663_PWR_DIG_2,
+		RT5668_PWR_ADC_S1F_SHIFT, 0, NULL, 0),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_SUPPLY("I2S", RT5663_PWR_DIG_1, RT5668_PWR_I2S1_SHIFT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_PGA("IF DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIFRX", "AIF Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIFTX", "AIF Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	/* DAC mixer before sound effect  */
+	SND_SOC_DAPM_MIXER("ADDA MIXL", SND_SOC_NOPM, 0, 0, rt5663_adda_l_mix,
+		ARRAY_SIZE(rt5663_adda_l_mix)),
+	SND_SOC_DAPM_MIXER("ADDA MIXR", SND_SOC_NOPM, 0, 0, rt5663_adda_r_mix,
+		ARRAY_SIZE(rt5663_adda_r_mix)),
+	SND_SOC_DAPM_PGA("DAC L1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DAC R1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* DAC Mixer */
+	SND_SOC_DAPM_SUPPLY("STO1 DAC Filter", RT5663_PWR_DIG_2,
+		RT5668_PWR_DAC_S1F_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("STO1 DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5663_sto1_dac_l_mix, ARRAY_SIZE(rt5663_sto1_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("STO1 DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5663_sto1_dac_r_mix, ARRAY_SIZE(rt5663_sto1_dac_r_mix)),
+
+	/* DACs */
+	SND_SOC_DAPM_SUPPLY("STO1 DAC L Power", RT5663_PWR_DIG_1,
+		RT5668_PWR_DAC_L1_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("STO1 DAC R Power", RT5663_PWR_DIG_1,
+		RT5668_PWR_DAC_R1_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_DAC("DAC L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC R", NULL, SND_SOC_NOPM, 0, 0),
+
+	/* Headphone*/
+	SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5663_hp_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+};
+
+static const struct snd_soc_dapm_widget rt5668_specific_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("LDO2", RT5663_PWR_ANLG_3,
+		RT5668_PWR_LDO2_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5668_PWR_VOL,
+		RT5668_PWR_MIC_DET_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("LDO DAC", RT5663_PWR_DIG_1,
+		RT5668_PWR_LDO_DACREF_SHIFT, 0, NULL, 0),
+
+	/* ASRC */
+	SND_SOC_DAPM_SUPPLY("I2S ASRC", RT5663_ASRC_1,
+		RT5668_I2S1_ASRC_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC ASRC", RT5663_ASRC_1,
+		RT5668_DAC_STO1_ASRC_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC ASRC", RT5663_ASRC_1,
+		RT5668_ADC_STO1_ASRC_SHIFT, 0, NULL, 0),
+
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("IN2P"),
+	SND_SOC_DAPM_INPUT("IN2N"),
+
+	/* Boost */
+	SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CBJ Power", RT5663_PWR_ANLG_3,
+		RT5668_PWR_CBJ_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("BST2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BST2 Power", SND_SOC_NOPM, 0, 0,
+		rt5668_bst2_power, SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMU),
+
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5668_recmix1l,
+		ARRAY_SIZE(rt5668_recmix1l)),
+	SND_SOC_DAPM_MIXER("RECMIX1R", SND_SOC_NOPM, 0, 0, rt5668_recmix1r,
+		ARRAY_SIZE(rt5668_recmix1r)),
+	SND_SOC_DAPM_SUPPLY("RECMIX1R Power", RT5663_PWR_ANLG_2,
+		RT5668_PWR_RECMIX2_SHIFT, 0, NULL, 0),
+
+	/* ADC */
+	SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_SUPPLY("ADC R Power", RT5663_PWR_DIG_1,
+		RT5668_PWR_ADC_R1_SHIFT, 0, NULL, 0),
+
+	/* ADC Mux */
+	SND_SOC_DAPM_PGA("STO1 ADC L1", RT5663_STO1_ADC_MIXER,
+		RT5668_STO1_ADC_L1_SRC_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("STO1 ADC R1", RT5663_STO1_ADC_MIXER,
+		RT5668_STO1_ADC_R1_SRC_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("STO1 ADC L2", RT5663_STO1_ADC_MIXER,
+		RT5668_STO1_ADC_L2_SRC_SHIFT, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("STO1 ADC R2", RT5663_STO1_ADC_MIXER,
+		RT5668_STO1_ADC_R2_SRC_SHIFT, 1, NULL, 0),
+
+	SND_SOC_DAPM_MUX("STO1 ADC L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5668_sto1_adcl_mux),
+	SND_SOC_DAPM_MUX("STO1 ADC R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5668_sto1_adcr_mux),
+
+	/* ADC Mix */
+	SND_SOC_DAPM_MIXER("STO1 ADC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5668_sto1_adc_r_mix, ARRAY_SIZE(rt5668_sto1_adc_r_mix)),
+
+	/* Analog DAC Clock */
+	SND_SOC_DAPM_SUPPLY("DAC Clock", RT5663_CHOP_DAC_L,
+		RT5668_CKGEN_DAC1_SHIFT, 0, NULL, 0),
+
+	/* Headphone out */
+	SND_SOC_DAPM_SWITCH("HPO Playback", SND_SOC_NOPM, 0, 0,
+		&rt5668_hpo_switch),
+};
+
+static const struct snd_soc_dapm_widget rt5663_specific_dapm_widgets[] = {
+	/* System Clock Pre Divider Gating */
+	SND_SOC_DAPM_SUPPLY("Pre Div Power", SND_SOC_NOPM, 0, 0,
+		rt5663_pre_div_power, SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD),
+
+	/* LDO */
+	SND_SOC_DAPM_SUPPLY("LDO ADC", RT5663_PWR_DIG_1,
+		RT5668_PWR_LDO_DACREF_SHIFT, 0, NULL, 0),
+
+	/* ASRC */
+	SND_SOC_DAPM_SUPPLY("I2S ASRC", RT5663_ASRC_1,
+		RT5663_I2S1_ASRC_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC ASRC", RT5663_ASRC_1,
+		RT5663_DAC_STO1_ASRC_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC ASRC", RT5663_ASRC_1,
+		RT5663_ADC_STO1_ASRC_SHIFT, 0, NULL, 0),
+
+	/* Boost */
+	SND_SOC_DAPM_PGA("BST1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* STO ADC */
+	SND_SOC_DAPM_PGA("STO1 ADC L1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("STO1 ADC L2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Analog DAC source */
+	SND_SOC_DAPM_MUX("DAC L Mux", SND_SOC_NOPM, 0, 0, &rt5663_alg_dacl_mux),
+	SND_SOC_DAPM_MUX("DAC R Mux", SND_SOC_NOPM, 0, 0, &rt5663_alg_dacr_mux),
+};
+
+static const struct snd_soc_dapm_route rt5663_dapm_routes[] = {
+	/* PLL */
+	{ "I2S", NULL, "PLL", rt5663_is_sys_clk_from_pll },
+
+	/* ASRC */
+	{ "STO1 ADC Filter", NULL, "ADC ASRC", rt5663_is_using_asrc },
+	{ "STO1 DAC Filter", NULL, "DAC ASRC", rt5663_is_using_asrc },
+	{ "I2S", NULL, "I2S ASRC", rt5663_i2s_use_asrc },
+
+	{ "ADC L", NULL, "ADC L Power" },
+	{ "ADC L", NULL, "ADC Clock" },
+
+	{ "STO1 ADC L2", NULL, "STO1 DAC MIXL" },
+
+	{ "STO1 ADC MIXL", "ADC1 Switch", "STO1 ADC L1" },
+	{ "STO1 ADC MIXL", "ADC2 Switch", "STO1 ADC L2" },
+	{ "STO1 ADC MIXL", NULL, "STO1 ADC Filter" },
+
+	{ "IF1 ADC1", NULL, "STO1 ADC MIXL" },
+	{ "IF ADC", NULL, "IF1 ADC1" },
+	{ "AIFTX", NULL, "IF ADC" },
+	{ "AIFTX", NULL, "I2S" },
+
+	{ "AIFRX", NULL, "I2S" },
+	{ "IF DAC", NULL, "AIFRX" },
+	{ "IF1 DAC1 L", NULL, "IF DAC" },
+	{ "IF1 DAC1 R", NULL, "IF DAC" },
+
+	{ "ADDA MIXL", "ADC L Switch", "STO1 ADC MIXL" },
+	{ "ADDA MIXL", "DAC L Switch", "IF1 DAC1 L" },
+	{ "ADDA MIXL", NULL, "STO1 DAC Filter" },
+	{ "ADDA MIXL", NULL, "STO1 DAC L Power" },
+	{ "ADDA MIXR", "DAC R Switch", "IF1 DAC1 R" },
+	{ "ADDA MIXR", NULL, "STO1 DAC Filter" },
+	{ "ADDA MIXR", NULL, "STO1 DAC R Power" },
+
+	{ "DAC L1", NULL, "ADDA MIXL" },
+	{ "DAC R1", NULL, "ADDA MIXR" },
+
+	{ "STO1 DAC MIXL", "DAC L Switch", "DAC L1" },
+	{ "STO1 DAC MIXL", "DAC R Switch", "DAC R1" },
+	{ "STO1 DAC MIXL", NULL, "STO1 DAC L Power" },
+	{ "STO1 DAC MIXL", NULL, "STO1 DAC Filter" },
+	{ "STO1 DAC MIXR", "DAC R Switch", "DAC R1" },
+	{ "STO1 DAC MIXR", "DAC L Switch", "DAC L1" },
+	{ "STO1 DAC MIXR", NULL, "STO1 DAC R Power" },
+	{ "STO1 DAC MIXR", NULL, "STO1 DAC Filter" },
+
+	{ "HP Amp", NULL, "DAC L" },
+	{ "HP Amp", NULL, "DAC R" },
+};
+
+static const struct snd_soc_dapm_route rt5668_specific_dapm_routes[] = {
+	{ "MICBIAS1", NULL, "LDO2" },
+	{ "MICBIAS2", NULL, "LDO2" },
+
+	{ "BST1 CBJ", NULL, "IN1P" },
+	{ "BST1 CBJ", NULL, "IN1N" },
+	{ "BST1 CBJ", NULL, "CBJ Power" },
+
+	{ "BST2", NULL, "IN2P" },
+	{ "BST2", NULL, "IN2N" },
+	{ "BST2", NULL, "BST2 Power" },
+
+	{ "RECMIX1L", "BST2 Switch", "BST2" },
+	{ "RECMIX1L", "BST1 CBJ Switch", "BST1 CBJ" },
+	{ "RECMIX1L", NULL, "RECMIX1L Power" },
+	{ "RECMIX1R", "BST2 Switch", "BST2" },
+	{ "RECMIX1R", NULL, "RECMIX1R Power" },
+
+	{ "ADC L", NULL, "RECMIX1L" },
+	{ "ADC R", NULL, "RECMIX1R" },
+	{ "ADC R", NULL, "ADC R Power" },
+	{ "ADC R", NULL, "ADC Clock" },
+
+	{ "STO1 ADC L Mux", "ADC L", "ADC L" },
+	{ "STO1 ADC L Mux", "ADC R", "ADC R" },
+	{ "STO1 ADC L1", NULL, "STO1 ADC L Mux" },
+
+	{ "STO1 ADC R Mux", "ADC L", "ADC L" },
+	{ "STO1 ADC R Mux", "ADC R", "ADC R" },
+	{ "STO1 ADC R1", NULL, "STO1 ADC R Mux" },
+	{ "STO1 ADC R2", NULL, "STO1 DAC MIXR" },
+
+	{ "STO1 ADC MIXR", "ADC1 Switch", "STO1 ADC R1" },
+	{ "STO1 ADC MIXR", "ADC2 Switch", "STO1 ADC R2" },
+	{ "STO1 ADC MIXR", NULL, "STO1 ADC Filter" },
+
+	{ "IF1 ADC1", NULL, "STO1 ADC MIXR" },
+
+	{ "ADDA MIXR", "ADC R Switch", "STO1 ADC MIXR" },
+
+	{ "DAC L", NULL, "STO1 DAC MIXL" },
+	{ "DAC L", NULL, "LDO DAC" },
+	{ "DAC L", NULL, "DAC Clock" },
+	{ "DAC R", NULL, "STO1 DAC MIXR" },
+	{ "DAC R", NULL, "LDO DAC" },
+	{ "DAC R", NULL, "DAC Clock" },
+
+	{ "HPO Playback", "Switch", "HP Amp" },
+	{ "HPOL", NULL, "HPO Playback" },
+	{ "HPOR", NULL, "HPO Playback" },
+};
+
+static const struct snd_soc_dapm_route rt5663_specific_dapm_routes[] = {
+	{ "I2S", NULL, "Pre Div Power" },
+
+	{ "BST1", NULL, "IN1P" },
+	{ "BST1", NULL, "IN1N" },
+	{ "BST1", NULL, "RECMIX1L Power" },
+
+	{ "ADC L", NULL, "BST1" },
+
+	{ "STO1 ADC L1", NULL, "ADC L" },
+
+	{ "DAC L Mux", "DAC L",  "DAC L1" },
+	{ "DAC L Mux", "STO DAC MIXL", "STO1 DAC MIXL" },
+	{ "DAC R Mux", "DAC R",  "DAC R1"},
+	{ "DAC R Mux", "STO DAC MIXR", "STO1 DAC MIXR" },
+
+	{ "DAC L", NULL, "DAC L Mux" },
+	{ "DAC R", NULL, "DAC R Mux" },